vue3+ts发布订阅模式
此次项目在写即时通讯的时候需要使用到发布订阅模式,一下在记录下项目中使用的方法
1.创建ts文件夹,写如下代码
class EventListenControl { container: any = {};//创建对象 on(evt: string, callback: Function) {//订阅(evt:需要监听的字段,callback:方法) if (!this.container[evt]) this.container[evt] = []; this.container[evt].push(callback);//每一次订阅,将键和方法存入对象中 } emit(evt: string, ...arg: any[]) {//发布 if (this.container.hasOwnProperty(evt))//在对象中找对应的键 this.container[evt].forEach((fn: Function) => {//调用对象中的方法返回数据 fn(...arg); }) } remove(evt: string, callback: Function) {//销毁当前订阅 if (this.container[evt] && this.container[evt] instanceof Array) { let idx = this.container[evt].findIndex((el: Function) => el == callback); if (idx >= 0) { this.container[evt].splice(idx, 1); } } } } export default EventListenControl;
2.在websocket中数据返回时,根据返回的字段进行信息发布
import EventListenControl from './control'
import {webSocketApi} from "@/config/axios.config"
const defaultURL = webSocketApi;
interface PrepareRequest {
key: string;
val:any;
}
//封装ws
class Ws extends EventListenControl {
url = "";//websocket地址
ws: WebSocket | null = null;//websocket
connected = false;//判断是否连接成功
pending = false;//判断是否在连接中
prepareList: PrepareRequest[] = [];//请求队列中的消息
heartbeat: any = null;//判断是否已经存在请求通道
loginApi: string;//登录api验证登录
constructor(loginApi?: string, url = defaultURL) {
super();
this.url = url;
// this.loginApi = loginApi;//这里注掉登录认证
this.loginApi = "";
}
connect() {//启动websocket
setTimeout(() => {
if (this.pending) return;
this.pending = true;
this.destroy();
const url = this.url;//websocket地址
try {
let ws = new WebSocket(url);
this.ws = ws;
ws.onmessage = (event) => {//接收websocket回传数据
if (this.connected) {
let data = JSON.parse(event.data);//数据结构成对象
this.emit(data.key, data.val);//data.key就是订阅传入的evt,data.content为数据
}
}
ws.onopen = (e) => {//连接成功
this.onconnect(e);
this.connected = true;
this.pending = false;
}
ws.onclose = e => {//关闭连接
if (ws === this.ws) {
this.pending = false;
this.connected = false;
}
}
ws.onerror = (e) => {//连接失败
console.log('onerror执行error事件,开始重连');
}
} catch (error) {
console.log(error);
}
}, 200)
}
postmessage(key : string, val: Object) {//外部调用的发送方法
if (this.ws && this.connected) {//判断队列是否有数据在传输或者连接终端,没的话发送
const dataString = JSON.stringify({
key,
val,
})
this.ws.send(dataString);
} else {//有的话就存到队列中
this.prepareList.push({ key, val });
}
}
destroy() {//关闭websocket
if (this.ws) {
this.ws.close();
}
if (this.heartbeat) {
clearInterval(this.heartbeat);
this.heartbeat = null;
}
}
onconnect(e: Event) {
if (!this.heartbeat) {
this.heartbeat = setInterval(() => {
this.postmessage("heartbeat", "ping");
}, 1000 * 60 * 2);
}
this.afterConnect(e);
}
afterConnect(e: Event) { }
}
//new websocket对象const createWebsocket = (loginApi?: string,) => {
// let ws = new Ws(loginApi);
let ws = new Ws();
return ws;
}
export {
createWebsocket,
};
export default Ws;
3.项目中使用,项目中引入第一步ts文件
//订阅 ws.on("chat", receiveMessage);//"chat"为约定字段,这里代指聊天,receiveMessage为方法 //回调方法,消息接收 const handleReceiveMessage = (res: any) => {//websocket返回的数据这里只接受类型为chat的 };