首页IT科技vue如何写一个聊天页面(Vue 使用 Vue-socket.io 实现即时聊天应用(Vue3连接原理分析))

vue如何写一个聊天页面(Vue 使用 Vue-socket.io 实现即时聊天应用(Vue3连接原理分析))

时间2025-05-04 20:33:30分类IT科技浏览5028
导读:目录...

目录

前言:

一           、新建 Vue3 项目

 二                、下载相关依赖

2.1 后台服务

2.2 前端连接

 2.3 启动项目

2.4 触发与接收事件

 2.5 原因分析

 三      、vue3 使用socket的原理

3.1 socket对象实例

3.2 socket 触发事件

 3.3 socket对象监听原生事件

3.4 vue-socket.io 源码解析

3.5 使用emitter.addListner() 监听事件***

四      、基于源码的 sockets 封装

 4.1 addListner()

4.2 removeListener()

4.3 main.js 处理

4.4 实现监听事件

 五                、总结

5.1 所有代码如下

前言:

技术讨论群【522121825】

根据小伙伴的留言           ,很多人希望能出一个 Vue3 的socket连接                 ,也有小伙伴对 room 的有兴趣     ,毕竟群聊的实现使用 room 更合理些           ,而不是广播           。今天                 ,记录一下 vue3 版本的Socket连接                。

一           、新建 Vue3 项目

 二      、下载相关依赖

npm i element-plus vue-socket.io --s

  ElementPlus 引入注册使用(与平常一样)     ,但是      ,socket.io 有些差异                 ,还是按照旧模式引入           ,有问题我们再思考原因:

2.1 后台服务

如【连接篇】中的node服务      ,可得到如下简介代码:

var app = require("express")(); var http = require("http").Server(app); var io = require("socket.io")(http, { allowEIO3: true, cors: { origin: "http://localhost:8080", methods: ["GET", "POST"], credentials: true, }, }); http.listen(3000, function () { console.log("listening on *:3000"); }); io.on("connection", function (socket) { console.log("a user connected"); });

2.2 前端连接

 2.3 启动项目

 看出                 ,现在项目能正常通信了           ,现在试试触发与接收事件:

2.4 触发与接收事件

io.on("connection", function (socket) { console.log("a user connected"); socket.emit("welcome", "welcome connect socket Serve."); socket.on("send", (data) => { console.log("客户端发送消息:", data); }); });

按照之前的思路,触发事件                 ,this.$socket.emit(xxx),

接收事件使用   sockets:{

        welcome(data){ xxxx}

},

但是!

  在 App.vue 中监听事件                 ,并没有收到数据,并且触发事件还报错了!

 2.5 原因分析

究其根源           ,我们应该清楚认识到                 ,vue2与vue3 的区别      。我们应该都听说过一句话     ,vue3 的实例对象更‘轻’了      。这也导致了vue3 的this           ,不能‘装下’ $socket                  ,我们将 this 输出如下:

vue2 输出 this:

vue2 输出 this.$socket 这个需要重点关注一下     ,vue3 的触发事件基于这个!!

 Vue3 输出this:

 vue3 输出this.$socket:

 这样是不是清晰看出      ,为什么不能使用 this.$socket触发事件与 sockets接收事件了吧                。 

 三                 、vue3 使用socket的原理

3.1 socket对象实例

我们之前都不关注socket本身                 ,只是利用其进行通信           ,现在看看socket自身:

/* SocketIOClient.Socket, */ const socket = new VueSocketIO({ debug: false, // debug调试      ,生产建议关闭 connection: "http://localhost:3000", }); console.log(socket);

输出socket:

 有小伙伴应该看到了                 ,这个实例对象           ,其实就是 vue2 中的 this.$socket!故而,vue2只不过是将socket实例放在vue实例上                 ,实际处理逻辑的                 ,还是socket实例自身,因此,我们可以使用socket对象来触发和监听事件了           。

3.2 socket 触发事件

根据刚才打印的 vue2 中的this.$socket           ,与vue3中的 socket.io是一样的                 ,故而     ,(vue2:this.$socket.emit())=  (vue3: socket.io.emit(eventName,someData)) 触发事件:

socket.io.emit("send", "测试 socket.io.emit事件");

 3.3 socket对象监听原生事件

 理论上           ,socket.io.emit触发方法                 ,应该使用 socket.io.on()监听事件     ,但事实不行      。socket.io.on是有特殊用处的      ,用于监听原生的默认事件:

// socket.io.on 不能用于监听 node 自定义事件 socket.io.on("welcome", (data) => { console.log("welcome",data); // 监听自定义事件 }); // 但是可以监听 默认事件 socket.io.on("connect", () => { console.log("connect"); // 监听 socket 连接事件 });

默认事件有:

3.4 vue-socket.io 源码解析

因为不能直接使用 socket.io.on() 监听事件                 ,我们就需要看看vue2 中是如何实现的           ,为啥会有 sockets:{},就能监听到事件                 。根据 vue2 中的 sockets:{subscribe}       , 在源码中直接搜索 sockets.subscribe                 ,将相关联的函数抽出           ,得到如下代码:

var n = { beforeCreate() { this.sockets || (this.sockets = {}), (this.sockets.subscribe = (t, e) => { this.$vueSocketIo.emitter.addListener(t, e, this); }), (this.sockets.unsubscribe = (t) => { this.$vueSocketIo.emitter.removeListener(t, this); }); }, mounted() { this.$options.sockets && Object.keys(this.$options.sockets).forEach((t) => { "subscribe" !== t && "unsubscribe" !== t && this.$vueSocketIo.emitter.addListener( t, this.$options.sockets[t], this ); }); }, beforeDestroy() { this.$options.sockets && Object.keys(this.$options.sockets).forEach((t) => { this.$vueSocketIo.emitter.removeListener(t, this); }); }, };

以上代码不解读了,不懂的伙伴可以留言讨论哈           。

为啥vue原来没有sockets属性,直接加sockets就能监听事件                 ,原理是使用了$options将sockets中的事件                 ,通过this.$vueSocketIo.emitter.addListener()添加到 socket对象上。

 this.$vueSocketIo.emitter.addListener(

            t,

            this.$options.sockets[t],

            this

          );

 模拟this.$vueSocketIo.emitter.addListener()的形式实现事件监听:

3.5 使用emitter.addListner() 监听事件***

/* SocketIOClient.Socket, */ const socket = new VueSocketIO({ debug: false, // debug调试,生产建议关闭 connection: "http://localhost:3000", }); socket.emitter.addListener("welcome", (data) => { console.log("addListener", data); });

 胜利的曙光!!!

但是还是报错了           ,源码还是使用了 this.$options 的形式处理                 ,故而需要处理一下:

也看了很多博主的方案     ,说需要修改源码           ,毕竟我们也找到了源码所在的位置                 ,但是不建议大家这么做     ,我们只需要基于源码再封装处理一下      ,就能满足我们的使用了

四           、基于源码的 sockets 封装

 4.1 addListner()

源码中无非就是 this.$options 和this我们获取不到                 ,那我们再封装一下           ,如下(新建 sockets.js):

export const registerSockets = (sockets, proxy) => { sockets && Object.keys(sockets).forEach((t) => { "subscribe" !== t && "unsubscribe" !== t && proxy.$socket.emitter.addListener(t, sockets[t], proxy); }); };

4.2 removeListener()

export const destroySockets = (sockets, proxy) => { sockets && Object.keys(sockets).forEach((t) => { proxy.$socket.emitter.removeListener(t, proxy); }); };

基于源码的 sockets 方法处理                 。

4.3 main.js 处理

import { createApp } from "vue"; import App from "./App.vue"; // 引入 ElementPlus import ElementPlus from "element-plus"; import "element-plus/dist/index.css"; import { registerSockets, destroySockets } from "./sockets"; // 引入 socket.io import VueSocketIO from "vue-socket.io"; const app = createApp(App); /* SocketIOClient.Socket, */ const socket = new VueSocketIO({ debug: false, // debug调试      ,生产建议关闭 connection: "http://localhost:3000", }); // 便于在任意位置获取到 socket 对象 app.config.globalProperties.$socket = socket; // 监听事件 app.config.globalProperties.$addSockets = registerSockets; // 移除事件 app.config.globalProperties.$removeSockets = destroySockets; app.use(ElementPlus).mount("#app");

4.4 实现监听事件

在需要监听的页面使用:

import { getCurrentInstance, onMounted, onBeforeUnmount } from "vue"; setup() { // 获取 当前实例对象 const { proxy } = getCurrentInstance(); // 触发事件 proxy.$socket.io.emit("send", "client send some data to node Serve."); // 定义监听node事件 const sockets = { welcome(data) { console.log(data); }, }; // 注册 node 事件 onMounted(() => { proxy.$sockets(sockets, proxy); }); // 注销 node 事件 onBeforeUnmount(() => { proxy.$removeSockets(sockets, proxy); }); },

能正常接收信息                 ,也能发送消息:

 五、总结

总的来看           ,要深入了解socket的源码,知道其实现方式                 ,基于源码                 ,将vue3的特性结合进去                 。现在的事件触发与接收,均使用 proxy 实现。

当然           ,也可以在app中                 ,直接获取子组件的所有 setup 中的sockes     ,进行统一注册           ,有更简洁的方式实现                 ,但是原理就是使用vue3 的proxy           。

5.1 所有代码如下:

main.js

import { createApp } from "vue"; import App from "./App.vue"; // 引入 ElementPlus import ElementPlus from "element-plus"; import "element-plus/dist/index.css"; import { registerSockets, destroySockets } from "./sockets"; // 引入 socket.io import VueSocketIO from "vue-socket.io"; const app = createApp(App); /* SocketIOClient.Socket, */ const socket = new VueSocketIO({ debug: false, // debug调试     ,生产建议关闭 connection: "http://localhost:3000", }); // 便于在任意位置获取到 socket 对象 app.config.globalProperties.$socket = socket; // 监听事件 app.config.globalProperties.$addSockets = registerSockets; // 移除事件 app.config.globalProperties.$removeSockets = destroySockets; app.use(ElementPlus).mount("#app");

sockets.js

export const registerSockets = (sockets, proxy) => { sockets && Object.keys(sockets).forEach((t) => { "subscribe" !== t && "unsubscribe" !== t && proxy.$socket.emitter.addListener(t, sockets[t], proxy); }); }; export const destroySockets = (sockets, proxy) => { sockets && Object.keys(sockets).forEach((t) => { proxy.$socket.emitter.removeListener(t, proxy); }); };

App.vue

<template> <div> app </div> </template> <script> import { getCurrentInstance, onMounted, onBeforeUnmount } from "vue"; export default { components: { HelloWorldVue }, setup() { const { proxy } = getCurrentInstance(); const sockets = { welcome(data) { console.log(data); }, }; proxy.$socket.io.emit("send", "client send some data to node Serve."); onMounted(() => { proxy.$addSockets(sockets, proxy); }); onBeforeUnmount(() => { proxy.$removeSockets(sockets, proxy); }); return {}; }, }; </script>

优化方案可以自己研究一下      ,基于 vue3 的socket rooms demo 下期更新                 。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
电脑管家监测流量(腾讯电脑管家流量监控怎么使用?)