1.store文件夹下新建一个index.js文件,稍后用到
//index.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
userInfo: null, // 保存用户信息,看具体情况自行编写
socketAction: '', //socket接受消息数据
},
mutations: {
//socket接受消息数据
setSocketAction(state, data) {
state.socketAction = data;
},
},
getters: {},
actions: {
},
modules: {},
});
2. 新建webSocket.vue文件(可直接cv使用,随便放个文件夹都行,后续引入注意路径)
//webWocket.vue
<template>
<div class="zzh_webSocket"></div>
</template>
<script>
import Vue from 'vue';
import { mapState } from 'vuex';
export default {
name: 'zzh_webSocket',
props: [],
components: {},
computed: {
...mapState({
userInfo: state => state.userInfo,
work_no: state => state.work_no,
}),
},
data() {
return {
websocketUrl: 'wx:xxxxx',
heartbeat: null, //心跳包定时器
//心跳包
heartbeatData: {
event_name: 'ping',
work_no: '',
},
isConnect: false, //链接状态
webSocket: null, //socket对象
// globalCallback: {}, //事件函数
reConnectNum: 0, //重连次数
};
},
methods: {
initWebSocket() {
this.heartbeatData.work_no = this.work_no;
//获取信息------------------------------------------
let that = this;
if ('WebSocket' in window) {
this.webSocket = new WebSocket(this.websocketUrl); //创建socket对象
//打开
this.webSocket.onopen = this.webSocketOpen;
//收信
this.webSocket.onmessage = this.webSocketOnMessage;
//关闭
this.webSocket.onclose = this.webSocketOnClose;
//连接发生错误的回调方法
this.webSocket.onerror = this.webSocketOnError;
//绑定到原型上方便调用,也可以绑定到vuex里面
Vue.prototype.$socketChatApi = {
sendSock: this.sendSock,
};
this.start();
}
},
start() {
this.isConnect = true;
this.reConnectNum++;
clearInterval(this.heartbeat);
this.heartbeat = null;
this.heartbeat = setInterval(() => {
//40秒心跳包
if (this.isConnect) {
this.reConnectNum = 0;
this.webSocketSend(this.heartbeatData);
} else {
clearInterval(this.heartbeat);
this.heartbeat = null;
}
}, 40000);
},
webSocketOpen() {
//首次握手 //这一段看后端需要绑定uid就写,不需要可以省略
this.webSocketSend({
event_name: 'bindUid',
work_no: this.heartbeatData.work_no,
});
// console.log('socket🙈🙈🙈------首次握手');
},
//收到消息
webSocketOnMessage(e) {
const res = JSON.parse(e.data); //根据自己的需要对接后端收到的数据进行处理
if (res.code == 1) {
console.log('error!!!', JSON.parse(JSON.stringify(res)));
return this.$message.error(res.msg || 'Response error');
} else if (res.event_name == 'ping') {
return;
} else {
console.log('socket🙈🙈🟢收:', JSON.parse(JSON.stringify(res)));
return this.$store.commit('setSocketAction', res);
}
},
//关闭时触发
webSocketOnClose(e) {
this.isConnect = false;
clearInterval(this.heartbeat);
console.log('socket🙈🙈🙈已经关闭 (code:' + e.code + ')- ' + this.reConnectNum, e);
if (this.reConnectNum < 3) {
this.initWebSocket();
} else {
//60s重连一次
clearTimeout(this.zzh_timer);
this.zzh_timer = null;
this.zzh_timer = setTimeout(() => {
if (!this.isConnect) {
console.log('socket🙈🙈🙈*********尝试自动连接************');
this.initWebSocket();
}
}, 60000);
}
},
webSocketOnError(e) {
clearInterval(this.heartbeat);
this.heartbeat = null;
this.isConnect = false; //断开后修改标识
console.log('socket🙈🙈🙈连接出错:', e);
},
//发送数据
webSocketSend(data) {
console.log('socket🙈🙈➡️发:', JSON.parse(JSON.stringify(data)));
this.webSocket.send(JSON.stringify(data)); //在这里根据自己的需要转换数据格式
},
//在其他需要socket地方调用的函数,用来发送数据及接受数据
sendSock(agentData, callback) {
//0 正在连接 1连接成功 2正在关闭 3已经关闭
if ([0, 2].includes(this.webSocket.readyState)) {
setTimeout(() => {
this.sendSock(agentData, callback);
}, 1000);
} else if ([1].includes(this.webSocket.readyState)) {
this.webSocketSend(agentData);
}
},
//在其他需要socket地方主动关闭socket(如退出登录) 根据需求自行更改
closeWebSocket(e) {
return;
this.sendSock({
event_name: 'logout',
});
setTimeout(_ => {
clearInterval(this.heartbeat);
this.heartbeat = null;
this.webSocket.close();
this.isConnect = false;
this.reConnectNum = 0;
}, 500);
},
//防抖
trottle(func, wait) {
let context, args;
// 之前的时间戳
let old = 0; // 默认为0
return function() {
context = this;
args = arguments;
// 获取当前的时间戳
let now = new Date().valueOf();
if (now - old > wait) {
// 立即执行
func.apply(context, args);
old = now;
}
};
},
},
created() {
this.initWebSocket();
},
mounted() {
let that = this;
//这三个函数的主要作用是起到无感刷新,例如电脑长时间不在睡眠状态socket可能会断开,所以监听鼠标移动重新链接
window.addEventListener('online', () => {
setTimeout(_ => {
if (!that.isConnect) {
console.log('socket🙈🙈🙈网络恢复----');
that.initWebSocket();
}
}, 3000);
});
window.addEventListener('offline', () => {
console.log('socket🙈🙈🙈网络离线===');
that.initWebSocket();
});
window.addEventListener(
'mousemove',
that.trottle(function() {
setTimeout(_ => {
if (!that.isConnect) {
console.log('socket🙈🙈🙈=====执行重连');
that.initWebSocket();
}
}, 1000);
}, 10000)
);
},
};
</script>
<style lang="less">
.zzh_webSocket {
}
</style>
3.使用
在需要用到socket的地方直接引入加载,可以放到index.vue或者app.vue都行,看具体使用场景
<template>
<div class="zzh_index">
<webSocket style="position: absolute;z-index: -1;"></webSocket>
</div>
</template>
<script>
import webSocket from '@/views/webSocket.vue';//注意修改路径
import { mapState } from 'vuex';
export default {
name: 'zzh_index',
props: [],
components: {
webSocket,
},
data() {
return {};
},
computed: {
...mapState({
userInfo: state => state.userInfo,
socketAction: state => state.socketAction, //重点!!!!!!!!!
}),
},
watch: {
//!!!!!这里可以监听到每次socket触发的事件,拿到数据
async socketAction(res) {
//返回的数据结构可与后端确定好就行,
//例如 {event_name:'bindUid',data:'aaa'}
switch (res.event_name) {
//想监听那个事件,就写相应case就行
case 'bindUid':
// this.$store.commit('SET_USERINFO', {
// id: res.data.work_no,
// displayName: res.data.user_name,
// avatar: res.data.avatar,
// });
break;
}
},
},
methods: {},
async created() {},
async mounted() {},
};
</script>
<style></style>
写的匆忙,有遗漏的地方滴滴我