在Laravel Websockets中如何检测其他用户是否已查看消息
实现方案
整体逻辑通过「已读动作上报+广播已读状态」的流程实现,具体操作步骤如下:
- 第一步:数据表结构调整
先给消息表新增2个字段:is_read:布尔类型,默认值false,标识消息是否被接收方查看read_user_ids:JSON类型,默认空数组,存储所有已查看该消息的用户ID
同时确保每条消息都关联了所属会话ID、发送用户ID字段。
- 第二步:新增已读事件与后端逻辑
- 新建广播事件类
MessageReadEvent,关联当前使用的会话私有频道message.{channel} - 新增一个后端接口,接收参数为「会话ID、当前登录用户ID」,逻辑为:将该会话下所有发送者不是当前用户、且
is_read=false的消息批量更新为is_read=true,同时把当前用户ID追加到read_user_ids中,更新完成后广播MessageReadEvent事件,事件携带已读用户ID、更新的消息ID列表参数。
- 新建广播事件类
- 第三步:前端逻辑修改
首先补充已读动作上报逻辑:在用户进入当前会话页面、聊天窗口聚焦、滚动到消息底部时,调用上面的后端接口上报已读。
然后修改现有Echo监听代码,新增已读事件监听,修改后代码如下:
$('.channels').each(function (i) { var channel = $(this).val(); console.log(channel, 'channel') window.Echo.private("message." + channel) .listen('MessagesEvent', (e) => { $('#chat').append(e.view) // 新消息加载后,如果当前页面是激活状态,直接上报已读 if(document.hasFocus()) { // 调用上报已读接口 axios.post('/message/read', {channel_id: channel}) } }) // 新增监听已读事件 .listen('MessageReadEvent', (e) => { // 遍历消息列表,把对应消息的未读标识替换为已读 e.message_ids.forEach(msgId => { $(`.msg-item[data-id="${msgId}"]`).find('.unread-tag').remove() }) }); window.Echo.join("message." + channel) .joining(user => { $(".status").css('background-color', '#00B3FF') // 对方加入会话时,如果有未读消息也可以触发一次已读上报 axios.post('/message/read', {channel_id: channel}) }) .leaving(user => { console.log(user, 'leaving'); $(".status").css('background-color', 'grey') }) }) // 补充窗口聚焦时的已读上报 window.addEventListener('focus', () => { let activeChannel = $('.channels.active').val() if(activeChannel) { axios.post('/message/read', {channel_id: activeChannel}) } })
- 可选优化:如果需要实时显示「对方正在输入」这类状态,也可以用presence频道的客户端事件实现,不需要额外请求后端,直接在前端触发
client-typing类事件,另一端监听即可。
内容的提问来源于stack exchange,提问作者Sukhwinder Sodhi
相关产品推荐
相关产品推荐

