使用websocket,封装到公共方法
首先创建一个socket.ts文件封装公共方法
/* * @Descripttion: 封装socket方法 * @version: * @Date: 2021-08-06 11:14:39 * @LastEditTime: 2021-10-26 14:06:34 */ import i18n from '@/locales' import store from '@/store' import { ElMessage } from 'element-plus' import { Base64 } from 'js-base64' const language = store.state.users.language // 当前用户信息,后台配置 const token = store.state.users.authorization // 获取验证信息,后台配置 interface socket { websocket: any connectURL: string socket_open: boolean hearbeat_timer: any hearbeat_interval: number is_reonnect: boolean reconnect_count: number reconnect_current: number ronnect_number: number reconnect_timer: any reconnect_interval: number init: (receiveMessage: Function | null) => any receive: (message: any) => void heartbeat: () => void send: (data: any, callback?: any) => void close: () => void reconnect: () => void } const socket: socket = { websocket: null, connectURL: `${process.env.VUE_APP_SOCEKT_URL}/websocket/v1/${language}/${token}`, // 开启标识 socket_open: false, // 心跳timer hearbeat_timer: null, // 心跳发送频率 hearbeat_interval: 45000, // 是否自动重连 is_reonnect: true, // 重连次数 reconnect_count: 3, // 已发起重连次数 reconnect_current: 1, // 网络错误提示此时 ronnect_number: 0, // 重连timer reconnect_timer: null, // 重连频率 reconnect_interval: 5000, init: (receiveMessage: Function | null) => { if (!('WebSocket' in window)) { ElMessage.warning('浏览器不支持WebSocket') return null } // 已经创建过连接不再重复创建 // if (socket.websocket) { // return socket.websocket // } socket.websocket = new WebSocket(socket.connectURL) socket.websocket.onmessage = (e: any) => { if (receiveMessage) { receiveMessage(e) } } socket.websocket.onclose = (e: any) => { clearInterval(socket.hearbeat_interval) socket.socket_open = false // 需要重新连接 if (socket.is_reonnect) { socket.reconnect_timer = setTimeout(() => { // 超过重连次数 if (socket.reconnect_current > socket.reconnect_count) { clearTimeout(socket.reconnect_timer) socket.is_reonnect = false return } // 记录重连次数 socket.reconnect_current++ socket.reconnect() }, socket.reconnect_interval) } } // 连接成功 socket.websocket.onopen = function() { socket.socket_open = true socket.is_reonnect = true // 开启心跳 // socket.heartbeat() } // 连接发生错误 socket.websocket.onerror = function() {} }, send: (data, callback = null) => { // 开启状态直接发送 if (socket.websocket.readyState === socket.websocket.OPEN) { socket.websocket.send(JSON.stringify(data)) if (callback) { callback() } // 正在开启状态,则等待1s后重新调用 } else { clearInterval(socket.hearbeat_timer) if (socket.ronnect_number < 1) { ElMessage({ type: 'error', message: i18n.global.t('chat.unopen'), duration: 0, }) } socket.ronnect_number++ } }, receive: (message: any) => { let params = Base64.decode(JSON.parse(message.data).data) params = JSON.parse(params) return params }, heartbeat: () => { if (socket.hearbeat_timer) { clearInterval(socket.hearbeat_timer) } socket.hearbeat_timer = setInterval(() => { let data = { languageId: store.state.users.language, authToken: store.state.users.authorization, content: 'ping', } var sendDara = { encryption_type: 'base64', data: Base64.encode(JSON.stringify(data)), } socket.send(sendDara) }, socket.hearbeat_interval) }, close: () => { clearInterval(socket.hearbeat_interval) socket.is_reonnect = false socket.websocket.close() }, /** * 重新连接 */ reconnect: () => { if (socket.websocket && !socket.is_reonnect) { socket.close() } socket.init(null) }, } export default socket
然后在聊天组件中引入
import socket from '@/utils/socket'
在挂载的生命周期放方法里面初始化socket
socket.init(methods.receiveMessage)
在这里 我们为websocket的onmessage方法传入了一个函数作为参数,这样的话我们在组件里面实现一个消息处理的方法
// 消息接收 receiveMessage(message: any) { const param = JSON.parse(Base64.decode(JSON.parse(message.data).data)) // 处理 赋值问题 const params = JSON.parse(JSON.stringify(param)) if (params) { switch (params.message) { case 'scheduleListFeedBack': break case 'onMessage': // 地磁获取消息列表 正则替换给过来的编码 break } } },
这样在onmessage里面的消息内容,我们可以通过方法传递回来,就可以在页面里面使用,其中的scheduleListFeedBack、onMessage是和后端定义的websocket的特定消息响应类型标识,可以拿到我们所需要的消息内容,进行逻辑处理。
这个方法是在socket.ts里面预先定义好的
socket.websocket.onmessage = (e: any) => { if (receiveMessage) { receiveMessage(e) } }
vue中封装websocket问题
每个组件页面都用到websocket,可以讲websocket封装起来,用到的组件页面一调用就好。
1.在untils文件夹下新建socket_service.js
export default class SocketService { static instance = null static get Instance () { if (!this.instance) { this.instance = new SocketService() } return this.instance } ws = null //存储回调函数 callBackMapping = {} //标识是否连接成功 connected = false //记录重试的次数 sendRetryCount = 0 //记录重新连接的次数 reconnectCount = 0 connect () { if (!window.WebSocket) { return console.log("您的浏览器不支持websocket!") } this.ws = new WebSocket('ws://192.168.0.88:8088') //连接服务端成功事件 this.ws.onopen = ()=> { console.log("连接服务端成功") this.connected = true this.reconnectCount = 0 } //连接服务端失败事件 this.ws.onclose = ()=> { console.log("连接服务端失败") this.connected = false this.reconnectCount++ setTimeout(()=>{ this.connect() },this.reconnectCount*500) } //从服务端获取数据 this.ws.onmessage = (msg)=> { console.log("从服务端获取到的数据" + msg.data) const recvData = JSON.parse(msg.data) const socketType = recvData.socketType if (this.callBackMapping[socketType]) { const action = recvData.action if (action === 'getData') { const realData = JSON.parse(recvData.data) this.callBackMapping[socketType].call(this, realData) } } } } //回调函数的注册 registerCallBack (socketType, callBack) { this.callBackMapping[socketType] = callBack } //取消回调函数 unRegisterCallBack (socketType) { this.callBackMapping[socketType] = null } send(data) { if (this.connected) { this.sendRetryCount = 0 this.ws.send(JSON.stringify(data)) } else { this.sendRetryCount++ setTimeout(()=>{ this.ws.send(JSON.stringify(data)) },this.sendRetryCount*500) } } }
2.在main.js里引用
import SocketService from '@/utils/socket_service' SocketService.Instance.connect() Vue.prototype.$socket = SocketService.Instance Vue.prototype.wsPath = 'ws://192.168.0.88:8088/' // websocket路径
2.在组件里调用$socket
mounted() { this.$socket.send({ action:'getData', socketType:'productivity', chartName:'product', value:'' }) }, created() { this.$socket.registerCallBack('productivity',this.getWsData) }, destroyed() { this.$socket.unRegisterCallBack('productivity') }, methods:{ getWsData (ret) { console.log('websocket接收到的值', event.ret) console.log(ret); this.cdata.category.forEach(item => { if (dataRec.materialClassifyName === item.materialClassifyName) { item.rate = dataRec.rate } }) }, }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持阿兔在线工具。