
对于一个大厅实时聊天我们都看惯不惯了,花了一天的时间结合nodejs-websocket和vue做了一个实时私聊的插件,当然代码方面有待改善。
现在简要讲解一下我的思路
一、规范传输
我的项目经验不多,但我觉得每个项目都要现设立一些规则,如果随心所欲的可能会导致自己跳到自己的坑。
我们先设定项目的json传输规定
//获取uid {type:'welcome',my_id:'我的uid'} //获取成员 {type:'member',members:['成员1','成员1']} //对话信息 {type:'chat',from:'来自uid',to:'发给uid',msg:'对话信息'}
二、服务器业务逻辑
// npm i nodejs-websocket let ws = require("nodejs-websocket") //str转json let json = str => { return (new Function('return '+str))() } //json转str let str = json =>{ return JSON.stringify(json) } // 实时聊天人数数组,通过随机数生成 let conns = [], message_welcome = {}, message_member = {}, message_between = {}, heart_beat = 9999, //要求每个连接每9999秒心跳一次,否则断线,建议调到50 let server = ws.createServer(function (conn) { //根据时间戳生成用户id uid let uid = str((new Date()).getTime()).slice(-6) //计算心跳时间 conn.heart_time = 0 let timer = setInterval(()=>{ if (conn.heart_time > heart_beat) { clearInterval(timer); conn.close() } conn.heart_time++ },1000) //保存用户id在全局数组conns中方便我们处理聊天对象信息 conns[uid] = conn message_welcome = {'my_id':uid,type:'welcome'} conn.sendText(str(message_welcome)) //如果有新的人员加入,广播数据给全部人 message_member = {'members':Object.keys(conns),type:'member'} for(var i in conns){ conns[i].sendText(str(message_member)) } //接受到发过来的信息 conn.on("text", function (text) { //重置心跳 conn.heart_time = 0 //判断发给谁 console.log(text) let data = json(text), to = data['to'], from = uid, msg = data['msg'] //存在发送的对象 console.log(str(Object.keys(conns)),to) if (Object.keys(conns).indexOf(to) != -1) { message_between = {type:'chat','from':from,'to':to,'msg':msg} console.log(str(message_between)) //发给别人 conns[to].sendText(str(message_between)) //发给自己 conns[from].sendText(str(message_between)) } }) //断开连接的回调 conn.on("close", function (code, reason) { //删除成员信息 delete conns[uid] //广播 message = {'members':Object.keys(conns),type:'member'} for(var i in conns){ conns[i].sendText(str(message_member)) } }) //处理错误事件信息 conn.on('error', function (err) { //异常conn就直接删除 conn.close() delete conns[uid] }) }).listen(8001);//8001端口
三、vuex管理websocket
因为websocket在项目中通常一个足以。所以直接扔给vuex比较稳。
我没有用onclose判断websocket状态,我改用WebSocket.readyState (0:正在连接,1:已连接,2:关闭中,3:已关闭)
因为这样的状态更深刻体现webscoket的状态。
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) // str转json let json = str => { return (new Function('return '+str))() } //json转str let str = json =>{ return JSON.stringify(json) } export default new Vuex.Store({ state: { WS:false,//websocket对象 WS_URL:'ws://127.0.0.1:8001', WS_RECONNECT:false,//自动重连 // HEART_BEAT:5,//每50秒心跳一次 HEART_MSG:'hello', }, mutations: { SOCKET_INIT(state,config={}){ if (!state.WS) { state.WS = new WebSocket(state.WS_URL) } for(var i in config){ state[i] = config[i] } }, SOCKET_MESSAGE(state,func){ return new Promise((resolve,reject)=>{ state.WS.onmessage=(data)=>{ // data = (new Function('return '+data))() resolve(func(json(data.data))) } //这个有问题,虽然很方便,但还是搁置 // state.WS.addEventListener('message',data=>{resolve(func(data))}) }) }, SOCKET_SEND(msg){ state.WS.send(str(msg)) }, SOCKET_HEART(state){ //设置心跳 if (state.HEART_BEAT > 0) { let timer = setInterval(()=>{ state.WS.send(state.HEART_MSG) //如果已经关闭就停止 if([2,3].indexOf(state.WS.readyState) !== -1){ clearInterval(timer) } },parseInt(state.HEART_BEAT)*1000) } } }, getters:{ }, actions: { SOCKET_INIT({state,commit},func){ return new Promise((resolve,reject)=>{ commit('SOCKET_INIT') state.WS.onerror = function (msg) { reject(msg) } let timer = setInterval(()=>{ //不是正在连接状态 if(state.WS.readyState!==0){ clearInterval(timer) //正在关闭,关闭 if([2,3].indexOf(state.WS.readyState) !== -1){ state.WS = false } //连接 if(state.WS.readyState===1){ resolve(state.WS) commit('SOCKET_HEART') commit('SOCKET_MESSAGE',func) } } },100) }) }, } })
四、调用webscoket
import { mapActions,mapState } from 'vuex' export default { name: 'vue-chat', computed:{ //websocket实例 ...mapState({'WS':'WS'}), }, methods:{ ...mapActions({socket:'SOCKET_INIT'}), sendMsg(str){ this.WS.send(str) }, handle_message(data){ //因为我在vuex中直接将其数据变为json,所以直接可以用 console.log(data) } } //一般直接放在加载完成的时候 mounted(){ let that = this //接受信息的时候 this.socket((data)=>{ that.handle_message(data) }) } }
git 代码:https://github.com/JeasonLaung/vue-chat
如果你觉得好,帮我star一个,谢谢大家
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/178925.html原文链接:https://javaforall.net
