vue.js 如何确定用户是否关闭了标签页以触发socket.io emit事件?

b5buobof  于 2023-08-07  发布在  Vue.js
关注(0)|答案(2)|浏览(130)

目前我正在学习Socket.IO,为了做到这一点,我决定尝试构建一个聊天应用程序。现在我有一个功能聊天,我试图创建一个列表,以显示所有连接的人的用户名聊天的一面。
当用户访问该页面时,一个输入字段要求输入用户名。当输入并提交用户名时,此函数执行:

setUsername(event){
    event.preventDefault()
    this.username = this.usernameInput
    this.usernameInput = null
    this.socket.emit('userJoined', this.username)
}

字符串
该函数将this.username设置为输入的用户名,然后发出具有this.username的用户已经加入,然后该函数将其推送到在线用户数组:

this.socket.on('userJoined', (user) => {
    this.onlineUsers.push(user)
});


到目前为止一切顺利,当用户加入聊天时,他们的用户名确实进入onlineUsers数组,但是,我不知道如何在他们关闭标签时将他们从这个数组中删除。为了做到这一点,我必须发射this.socket.emit('userLeft', this.username),但我不知道我应该如何发射它。有没有一个函数,我可以把这个代码,总是执行时,用户关闭他的标签?
我在下面提供了完整的代码:

<template>
    <div class="home">
        {{ onlineUsers }}
        <div class="wrapper">
            <div class='username-container' v-if='!this.username'>
                <form class='username-form' @submit='setUsername($event)'>
                    <input class='username-input' v-model="usernameInput" placeholder="Pick a username">
                    <div class='enter-chat' @click='setUsername($event)'>Enter chat</div>
                </form>
            </div>
            <div class='chat-container' v-else>
                <div class="chat">
                    <div class="messages">
                        <div class='message-container' v-for='message in messages'>
                            <div class="username-date-container">
                                <p class='username'>{{ message.username }}</p>
                                <p class='date'>{{ getTimeAndDate(message.time) }}</p>
                            </div>
                            <p class='message'>{{ message.message }}</p>
                        </div>
                    </div>
                </div>
                <form @submit='sendMessage($event)'>
                    <input class='message-input' v-model="message" placeholder="Type a message">
                </form>
            </div>
        </div>
    </div>
</template>

<script>
    import io from 'socket.io-client'
    import moment from 'moment'

    export default {
        data(){
            return {
                socket: io.connect('http://localhost:3000'),
                usernameInput: null,
                username: null,
                messages: [],
                message: null,
                onlineUsers: []
            }
        },
        methods: {
            setUsername(event){
                event.preventDefault()
                this.username = this.usernameInput
                this.usernameInput = null
                this.socket.emit('userJoined', this.username)
            },
            sendMessage(event){
                event.preventDefault()
                let fullMessage = {
                    username: this.username,
                    message: this.message,
                    time: Date.now()
                }
                this.socket.emit('message', fullMessage)
                this.message = null
            },
            getTimeAndDate(timestamp){
                return moment(timestamp).subtract(10, 'days').calendar();
            }
        },
        mounted(){
            this.socket.on('message', (message) => {
                this.messages.push(message)
            });
            this.socket.on('userJoined', (user) => {
                this.onlineUsers.push(user)
            });
            this.socket.on('userLeft', (user) => {
                this.onlineUsers.pop(user)
            });
        }
    }
</script>

vsikbqxv

vsikbqxv1#

试试这个:

window.addEventListener("beforeunload", function(event) { ... });
window.onbeforeunload = function(event) { ... };

字符串
https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload

6pp0gazn

6pp0gazn2#

我想我已经找到了一个非常坚实的解决方案使用Map。

所有服务器端

import type { NextApiRequest } from 'next'
import type { ClientToServerEvents, InterServerEvents, NextApiResponseWithSocket, ServerToClientEvents, SocketData } from '../../types/socket'
import { Server } from 'socket.io'

let socketsData = new Map()

const socket = (req: NextApiRequest, res: NextApiResponseWithSocket) => {
  // socket initialisation, blah blah blah

  io.on('connection', socket => {
    // all the other events you need (`sendMessage`, `createRoom` and so on)

    socket.on('disconnect', () => {
      const { username, roomId } = socketsData.get(socket.id)
      io.to(roomId).emit('userLeft', `${username} has left the room`)
      socketsData.delete(socket.id)
    })
  })

  res.status(200).send('Setting up the socket.')
}

export default socket

字符串
正如您所看到的,如果您需要特定于套接字的东西,您可以将所有数据存储在一个Map中。

相关问题