【基于VUE的实时聊天(私聊)】
对于一个大厅实时聊天我们都看惯不惯了,花了一天的时间结合nodejs-websocket和vue做了一个实时私聊的插件,当然代码方面有待改善。 现在简要讲解一下我的思路一、规范传输我的项目经验不多,但我觉得每个项目都要现设立一些规则,如果随心所欲的可能会导致自己跳到自己的坑。我们先设定项目的json传输规定//获取uid{type:'welcome',my_id...
·
对于一个大厅实时聊天我们都看惯不惯了,花了一天的时间结合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一个,谢谢大家
更多推荐
已为社区贡献3条内容
所有评论(0)