Vue uses Vue-socket.io to implement instant chat application (analysis of Vue3 connection principle)

Table of contents

Foreword:

1. Create a new Vue3 project

 2. Download related dependencies

2.1 Background service

2.2 Front-end connection

 2.3 Start the project

2.4 Triggering and receiving events

 2.5 Cause Analysis

 3. The principle of vue3 using socket

3.1 socket object instance

3.2 socket trigger event

 3.3 The socket object listens to native events

3.4 vue-socket.io source code analysis

3.5 Use emitter.addListner() to listen to events***

4. Sockets encapsulation based on source code

 4.1 addListner()

4.2 removeListener()

4.3 main.js processing

4.4 Realize monitoring events

 V. Summary

5.1 All codes are as follows


Foreword:

Technical discussion group【522121825】

According to the comments of the friends, many people hope to have a Vue3 socket connection, and some friends are interested in the room. After all, it is more reasonable to use the room instead of the broadcast to realize the group chat. Today, record the Socket connection of the vue3 version.

1. Create a new Vue3 project

 2. Download related dependencies

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

  ElementPlus introduces registration and use (as usual), but socket.io has some differences, and it is still introduced according to the old model. If there is a problem, let's think about the reason again:

2.1 Background service

For example , the node service in [Connection] can get the following introduction code:

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 Front-end connection

 2.3 Start the project

 

 It can be seen that the project can now communicate normally, now try to trigger and receive events:

2.4 Triggering and receiving events

io.on("connection", function (socket) {
  console.log("a user connected");

  socket.emit("welcome", "welcome connect socket Serve.");

  socket.on("send", (data) => {
    console.log("客户端发送消息:", data);
  });
});

According to the previous idea, trigger the event, this.$socket.emit('xxx'),

Receive events using sockets:{

        welcome(data){ xxxx}

},

but!

  Listening to the event in App.vue did not receive any data, and an error was reported when the event was triggered!

 2.5 Cause Analysis

Investigating the root cause, we should clearly realize the difference between vue2 and vue3. We should all have heard the saying that the instance object of vue3 is lighter . This also leads to the this of vue3, which cannot be 'installed' $socket, we output this as follows:

vue2 outputs this:

Vue2 outputs this.$socket [ This needs to be focused on, the trigger event of vue3 is based on this! !

 Vue3 outputs this:

 Vue3 outputs this.$socket:

 Does this make it clear why you can't use this.$socket to trigger events and sockets to receive events? 

 3. The principle of vue3 using socket

3.1 socket object instance

We didn't pay attention to the socket itself before, just use it for communication, now look at the socket itself:

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

output socket:

 Some friends should have seen that this instance object is actually this.$socket in vue2! Therefore, vue2 just puts the socket instance on the vue instance. The actual processing logic is still the socket instance itself. Therefore, we can use the socket object to trigger and monitor events.

3.2 socket trigger event

According to this.$socket in vue2 just printed, it is the same as socket.io in vue3, so (vue2: this.$socket.emit()) = (vue3: socket.io.emit('eventName' ,someData)) fires the event:

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

 3.3 The socket object listens to native events

 In theory, the socket.io.emit trigger method should use socket.io.on() to listen to events, but it doesn't work. socket.io.on is special for listening to native default events:

// socket.io.on 不能用于监听 node 自定义事件
socket.io.on("welcome", (data) => {
  console.log("welcome",data); // 监听自定义事件
});

// 但是可以监听 默认事件
socket.io.on("connect", () => {
  console.log("connect"); // 监听 socket 连接事件
});

Default events are:

3.4 vue-socket.io source code analysis

Because we cannot directly use socket.io.on() to monitor events, we need to see how it is implemented in vue2, why there are sockets: {}, and we can monitor events. According to sockets in vue2: {subscribe}, directly search for sockets.subscribe in the source code, extract the associated functions, and get the following code:

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);
      });
  },
};

The above code is not interpreted, and partners who don’t understand can leave a message to discuss.

Why does vue not have the sockets attribute in the first place, and you can listen to events by adding sockets directly. The principle is to use $options to add events in sockets to the socket object through this.$vueSocketIo.emitter.addListener().

 this.$vueSocketIo.emitter.addListener(
            t,
            this.$options.sockets[t],
            this
          );

 Simulate this.$vueSocketIo.emitter.addListener() to implement event monitoring:

3.5 Use emitter.addListner() to listen to events***

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

socket.emitter.addListener("welcome", (data) => {
  console.log("addListener", data);
});

 The dawn of victory! ! !

However, an error is still reported, and the source code is still processed in the form of this.$options, so it needs to be processed:

[ I also read the proposals of many bloggers and said that the source code needs to be modified. After all, we have also found the location of the source code, but it is not recommended for everyone to do this. We only need to package and process it based on the source code to meet our needs. ]

4. Sockets encapsulation based on source code

 4.1 addListner()

The source code is nothing more than this.$options and this, which we can’t get, so let’s encapsulate it again, as follows (new 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);
    });
};

Source-based sockets method handling.

4.3 main.js processing

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 Realize monitoring events

Use on the page that needs to be monitored:

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);
    });
  },

Can receive information normally, and can also send messages:

 

 V. Summary

In general, it is necessary to deeply understand the source code of socket, know its implementation method, and combine the features of vue3 based on the source code. The current event triggering and receiving are implemented using proxy.

Of course, you can also directly obtain the sockets in all the setups of the subcomponents in the app, and perform unified registration. There is a more concise way to achieve this, but the principle is to use the proxy of vue3.

5.1 All codes are as follows:

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>

The optimization scheme can be studied by yourself, the socket rooms demo based on vue3 will be updated in the next issue.

Guess you like

Origin blog.csdn.net/weixin_47746452/article/details/126827806