广播到房间的套接字 IO 无法正常工作

Socket IO broadcasting to room is not functioning correctly

如果这是一个模糊的问题,请让我知道,以便我指定。真想绕过这个树桩

我已经阅读了一些关于如何正确地将消息广播到客户房间的备忘单。我的参考是:https://github.com/socketio/socket.io/blob/master/docs/emit.md.

描述我的问题: 聊天页面正确显示了发送按钮,但是一旦我点击发送,就什么也没有发送。

有趣的是,每当我不使用房间时,只要使用默认命名空间,我就可以收到消息。

知道发生了什么事吗?谢谢!!

server.js

io.on('connection', function(socket) {
    global.rooms = 'room1';
    socket.on('subscribe', function(room) {
        socket.join(rooms);
        console.log(socket.id + 'joining room', rooms)
    })
    socket.on('chat', function(data) {
        io.to(rooms).emit('chat', data);
  })
})

chat.jade

extends layout

block content

 h2.page-header Chat Page
 div(id='the-chat')
  div(id='chat-window')
   div(id='output')
  input(id='handle', type='text', value = user.name, style= 'width: 0px; visibility: hidden;')
  input(id='message', type='text', placeholder='message')
  button(id='send' value='Send') Send

  //imports the socket.io functionality on the client side for the chat.jade application
  script(src="/socket.io/socket.io.js")

  script.

    //variable created that mirrors connection made in the backend

    //matches the connection made in the server side
    var socket = io.connect('http://localhost:3000')

    //Query dom
    var message = document.getElementById('message')
    var handle = document.getElementById('handle')
    var btn = document.getElementById('send')
    var output = document.getElementById('output')

    //emit events
    btn.addEventListener('click', function() {
      socket.emit('chat', {
        message: message.value,
        handle: handle.value
      })
    })


    socket.on('chat', function(data) {
      output.innerHTML += '<p><strong>' + data.handle + ': </strong>' + data.message + '</p>';
      document.getElementById('message').value = "";
    })

Home.jade

extends layout


block content

    h2.page-header(style = "text-align: center;").
        Home Page

    if (user.isTutor)
        b(style = "text-align: center;")
            form(method='post', action = '/home/available')
                input.btn.btn-primary(type = 'submit',name='isAvailable', value = 'Available', id = 'button4')
            form(method='post', action = '/home/unavailable')
                input.btn.btn-primary(type = 'submit',name='isUnavailable', value = 'Unavailable', id = 'button5')  
    script(src="/socket.io/socket.io.js")
    script.
        var btn = document.getElementById('button4')
        //var space = '#{user.room}'
        var socket = io.connect()
        btn.addEventListener('click', function() {
            socket.emit('subscribe', 'room1')
        })

    div(id = 'magic')
        form(method='get')
            if (user.hasApplied)
                input.btn.btn-primary(type = 'submit', onclick = "javascript: form.action = '/findatutor';" name='find', value = 'Find a Tutor', class = 'middle', id = 'button7')

            else if (user.hasApplied == false)
                input.btn.btn-primary(type = 'submit', onclick = "javascript: form.action = '/findatutor';" name='find', value = 'Find a Tutor', id = 'button1')
                input.btn.btn-primary(type = 'submit', onclick = "javascript: form.action = '/apply';"  name='become', value = 'Become a Tutor', id = 'button2')

Home.js

router.post('/available', ensureAuthenticated, (req,res,next) => {
    var io = res.locals['socketio']
    db.collection('DefaultUser').update({_id: req.user._id}, {$set: {isAvailable: true}});
    res.redirect('../chat')
})

尝试

io.in(rooms).emit('chat', data);

global.rooms = 'room1';

下缺少这个
var rooms = global.rooms

更长的答案:至少我可以看到,您已经在全局对象上添加了 "rooms" 作为 属性(idk,其中定义了 'global' 本身,但是如果它是没有抛出错误,我假设你在上面定义了它)。虽然它是 属性,但您用作命名空间的变量 'rooms' 在您调用它时并未定义,因此它不知道在哪里发出消息。

更多答案:此外,如果您打算向 global.rooms 添加额外的房间,我认为您可能希望使用散列列表来存储它们,以便您可以轻松地访问它们 global.rooms[room],以及轻松将新房间添加到列表中,即 global.rooms[room.name] = room

问题是您没有指定在何处呈现消息。据我了解,您创建房间没有问题,所以我将逐步说明之后如何处理。

根据您的代码,这是服务器和客户端之间用于发送消息的通信

//server.js
 socket.on('chat', function(data) {
        io.to(rooms).emit('chat', data);
  })
//chat.jade
btn.addEventListener('click', function() {
      socket.emit('chat', {
        message: message.value,
        handle: handle.value
      })
    })

第一个客户端正在向服务器发送消息(输入输入框),当服务器收到消息时,它必须向所有其他客户端发送相同的消息。一旦客户收到此消息,客户就必须弄清楚如何显示它。但是当服务器发送接收到的消息时,你必须发起一个新的事件。让我们称之为显示。所以你的代码应该是这样的:

//server.js
//i always use arrow functions, but I will follow along your code
     socket.on('chat', function(data) { 
            io.to(rooms).emit('display', data);
      })

现在您的客户端应该正在侦听此事件并且应该处理在何处显示它:

//chat.jade

socket.on('display', (data) => {
    const displayedMessage = pug.render(messageTemplate, {
        message: data.message,
    })
    $messages.insertAdjacentHTML('beforeend', displayedMessage)
})

由于 Jade 已重命名为 pug,因此我在这里使用 pug。所以我将在脚本标签中将 {message: data.message} 渲染到 html 然后将其放入 DOM ELEMENT $message.

我不确定你想在哪里呈现 handle:handle.value 我将只展示如何显示消息。同样,你也能搞定。

现在 messageTemplate$messages 和 insertAdjacentHTML() 是什么?

在您的 html

中创建一个 div 标签和一个脚本标签
//this is where you are gonna display the message
<div id="messages" class="chat__messages"></div>

<!-- template messages -->
    <script id="message-template" type="text/html">
      <div>
          <p>{{message}}</p>
      </div>
    </script>

//chat.jade

const $messages = document.getElementById("messages");
const messageTemplate = document.getElementById("message-template").innerHTML;

insertAdjacentHTML() 方法将文本 HTML 插入指定位置。你可以在这里得到更多的解释和例子:

https://www.w3schools.com/jsref/met_node_insertadjacenthtml.asp

socket io代码看起来又长又复杂,但如果你知道逻辑并一步一步地进行,就会很容易实现它。