Socket.io接收的客户端消息如何在EJS渲染中全局使用
解决方案
socket.on('chatMessage')回调内的msg是局部作用域变量,根路由无法直接访问。聊天场景需要存储历史消息而非单条临时消息,按以下步骤修改即可:
步骤1:定义全局可访问的消息存储
在server.js顶层作用域(和port、app这些变量同级,不要写在路由或socket回调内部)定义存储容器:
// 放在const port = process.env.PORT || 3000 这行下面即可 const messageHistory = [];
步骤2:收到消息时同步存入全局存储
修改socket.on('chatMessage')的回调逻辑,收到消息后先存入数组再广播:
//listen chatMessage socket.on('chatMessage', msg =>{ // 新消息写入全局历史数组 messageHistory.push(msg); io.emit('message',msg); console.log(msg); });
如果需要把用户上下线、欢迎语这类系统消息也展示给新进入的用户,在对应的socket.emit/io.emit触发位置,同步把消息内容push到messageHistory即可。
步骤3:根路由传入消息数据给EJS模板
修改根路由的渲染逻辑,直接传入全局存储的消息数组:
app.get("/", (req,res) =>{ res.render("index",{messagedata: messageHistory}); });
步骤4:前端完成历史消息渲染+实时消息追加
注意:路由渲染只在用户首次打开页面时执行,用来加载历史消息;后续的新消息靠Socket.io实时推送更新,两部分逻辑都要补上:
- 在EJS模板中遍历
messagedata渲染初始历史消息 - 修改客户端
socket.on('message')回调,把收到的实时消息追加到页面消息列表中
参考客户端实现代码:
const socket = io(); const user_send =document.querySelector(".send-btn"); const user_msg=document.querySelector(".input-msg"); // 获取页面上的消息列表容器,对应HTML里<ul class="msg-container"></ul>这类结构 const msgContainer = document.querySelector(".msg-container"); // 渲染EJS传入的历史消息 <% messagedata.forEach(function(msg){ %> const msgItem = document.createElement('li'); msgItem.textContent = '<%= msg %>'; msgContainer.appendChild(msgItem); <% }) %> //message from server socket.on('message',message=>{ console.log(message); // 把实时收到的消息追加到页面 const msgItem = document.createElement('li'); msgItem.textContent = message; msgContainer.appendChild(msgItem); // 发送后清空输入框 user_msg.value = ''; }) //getting socketid from server socket.on('socketid',socketid=>{ console.log(socketid); }); //ading eventlistner in message send button user_send.addEventListener("click",()=>{ //get mesage from text filed const msg = user_msg.value; // 空消息不发送 if(!msg.trim()) return; //emit message to server socket.emit('chatMessage',msg); });
补充说明
- 当前实现的消息存在服务端内存中,服务重启后所有消息会清空。如果需要永久保存消息,可以用你已经引入的
mysql模块,收到消息时同步写入数据库,根路由渲染时从数据库读取消息传入模板即可。 - 不建议用单个全局字符串变量存储单条消息,否则新用户进入页面只能看到最后一条消息,不符合聊天应用的使用逻辑。如果确实只需要最新一条消息,把顶层的数组替换为
let latestMsg = '',收到消息时赋值latestMsg = msg,路由传入latestMsg即可。
内容的提问来源于stack exchange,提问作者Kushal Chapagain
相关产品推荐
相关产品推荐

