iis websocket 模块未启用_Vue合理配置WebSocket并实现群聊

34537c0fb6f270df9dd8ffee334509f1.png

学习的动力源于兴趣,愿你在学习新知识时,动力源于兴趣而并非其它

前言

写JQuery项目时,使用websocket很简单,不用去考虑模块化,组件之间的访问问题,面向文档编程即可,在Vue项目中使用时,远远没有想象中的那么简单,需要考虑很多场景,本篇文章将与各位开发者分享下vue-native-websocket库的使用以及配置,用其实现群聊功能。先看下最终实现的效果

c2fed4b426b8b40f815871fceecaab75.gif

安装依赖

本文中对于vue-native-websocket库的讲解,项目中配置了vuex,对其不了解的开发者请移步官方文档,如果选择继续阅读本篇文章会比较吃力。

  • vue-native-websocket安装
# yarn | npm 安装yarn add vue-native-websocket | npm install vue-native-websocket --save复制代码
  • 安装成功
b8666f1ce9549de538215183ed1ea4bf.png

配置插件

  • main.js中进行导入
import VueNativeSock from 'vue-native-websocket'复制代码
  • 使用VueNativeSock插件,并进行相关配置
// main.js// base.lkWebSocket为你服务端websocket地址Vue.use(VueNativeSock,base.lkWebSocket,{  // 启用Vuex集成,store的值为你的vuex  store: store,  // 数据发送/接收使用使用json格式  format: "json",  // 开启自动重连  reconnection: true,  // 尝试重连的次数  reconnectionAttempts: 5,  // 重连间隔时间  reconnectionDelay: 3000,  // 将数据进行序列化,由于启用了json格式的数据传输这里需要进行重写  passToStoreHandler: function (eventName, event) {    if (!eventName.startsWith('SOCKET_')) { return }    let method = 'commit';    let target = eventName.toUpperCase();    let msg = event;    if (this.format === 'json' && event.data) {      msg = JSON.parse(event.data);      if (msg.mutation) {        target = [msg.namespace || '', msg.mutation].filter((e) => !!e).join('/');      } else if (msg.action) {        method = 'dispatch';        target = [msg.namespace || '', msg.action].filter((e) => !!e).join('/');      }    }    this.store[method](target, msg);    this.store.state.socket.message = msg;  }});复制代码
  • vuex的相关配置:mutations和actions添加相关函数
// vuex配置文件import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex);export default new Vuex.Store({  state: {    token:"",    userID:"",    // 用户头像    profilePicture: "",    socket: {      // 连接状态      isConnected: false,      // 消息内容      message: '',      // 重新连接错误      reconnectError: false    }  },  mutations: {    SOCKET_ONOPEN (state, event)  {      // 连接打开触发的函数      Vue.prototype.$socket = event.currentTarget;      state.socket.isConnected = true    },    SOCKET_ONCLOSE (state, event)  {      // 连接关闭触发的函数      state.socket.isConnected = false;      console.log(event);    },    SOCKET_ONERROR (state, event)  {      // 连接发生错误触发的函数      console.error(state, event)    },    SOCKET_ONMESSAGE (state, message)  {      // 收到消息时触发的函数      state.socket.message = message    },    SOCKET_RECONNECT(state, count) {      // 重新连接触发的函数      console.info(state, count)    },    SOCKET_RECONNECT_ERROR(state) {      // 重新连接失败触发的函数      state.socket.reconnectError = true;    },  },  actions: {    customerAdded (context) {      // 新连接添加函数      console.log('action received: customerAdded');      console.log(context)    }  },  modules: {  }})复制代码

至此vue-native-websocket配置结束,如需了解更多配置方法,请移步npm仓库

使用插件并实现群聊

  • 在消息发送接收组件中添加onmessage监听(mounted生命周期中)
// 监听消息接收this.$options.sockets.onmessage = (res)=>{    // res.data为服务端返回的数据    const data = JSON.parse(res.data);    // 200为服务端连接建立成功时返回的状态码(此处根据真实后端返回值进行相应的修改)    if(data.code===200){        // 连接建立成功        console.log(data.msg);    }else{        // 获取服务端推送的消息        const msgObj = {            msg: data.msg,            avatarSrc: data.avatarSrc,            userID: data.userID        };        // 渲染页面:如果msgArray存在则转json        if(lodash.isEmpty(localStorage.getItem("msgArray"))){            this.renderPage([],msgObj,0);        }else{            this.renderPage(JSON.parse(localStorage.getItem("msgArray")),msgObj,0);        }    }};复制代码
  • 实现消息发送
// 消息发送函数sendMessage: function (event) {    if (event.keyCode === 13) {        // 阻止编辑框默认生成div事件        event.preventDefault();        let msgText = "";        // 获取输入框下的所有子元素        let allNodes = event.target.childNodes;        for(let item of allNodes){            // 判断当前元素是否为img元素            if(item.nodeName==="IMG"){                msgText += `/${item.alt}/`;            }            else{                // 获取text节点的值                if(item.nodeValue!==null){                    msgText += item.nodeValue;                }            }        }        // 消息发送: 消息内容、状态码、当前登录用户的头像地址、用户id        this.$socket.sendObj({msg: msgText,code: 0,avatarSrc: this.$store.state.profilePicture,userID: this.$store.state.userID});        // 清空输入框中的内容        event.target.innerHTML = "";    }}复制代码
  • 实现页面渲染
// 渲染页面函数renderPage: function(msgArray,msgObj,status){    if(status===1){        // 页面第一次加载,如果本地存储中有数据则渲染至页面        let msgArray = [];        if(localStorage.getItem("msgArray")!==null){            msgArray = JSON.parse(localStorage.getItem("msgArray"));            for (let i = 0; i
  • 实现消息解析
// 消息解析messageParsing: function(msgObj){    // 解析接口返回的数据进行渲染    let separateReg = /(/[^/]+/)/g;    let msgText = msgObj.msgText;    let finalMsgText = "";    // 将符合条件的字符串放到数组里    const resultArray = msgText.match(separateReg);    if(resultArray!==null){        for (let item of resultArray){            // 删除字符串中的/符号            item = item.replace(///g,"");            for (let emojiItem of this.emojiList){                // 判断捕获到的字符串与配置文件中的字符串是否相同                if(emojiItem.info === item){                    const imgSrc = require(`../assets/img/emoji/${emojiItem.hover}`);                    const imgTag = ``;                    // 替换匹配的字符串为img标签:全局替换                    msgText = msgText.replace(new RegExp(`/${item}/`,'g'),imgTag);                }            }        }        finalMsgText = msgText;    }else{        finalMsgText = msgText;    }    msgObj.msgText = finalMsgText;    // 渲染页面    this.senderMessageList.push(msgObj);    // 修改滚动条位置    this.$nextTick(function () {        this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight;    });}复制代码
  • DOM结构

通过每条消息的userID和vuex中的存储的当前用户的userID来判断当前消息是否为对方发送

复制代码

群聊实现思路解析

  • 消息组件挂载完成后:从本地存储中读取消息记录,如果存在则将消息渲染至页面
  • 监听消息接收:服务端推送消息后触发onmessage事件
  • 获取到服务端推送的消息后:从本地存储中读取消息记录
  • 如果本地存储中存在消息记录:更新本地存储中对消息记录,将当前消息对象放进消息记录中,并渲染页面
  • 如果本地存储中不存在消息记录:在本地存储中创建消息记录字段,将当前消息对象放进消息记录中,并渲染页面
  • 触发消息发送:使用this.$socket.sendObj方法,传当前用户的相关信息,推送至服务端websocket服务
  • 服务端收到消息后:将当前用户发送的消息进行处理,并发送给与服务器取得连接的客户端。
  • 客户端收到消息后:触发onmessage事件

更多用法

最后更新时间: 2020年2月1日

手动连接websockt服务

  • 开启手动连接,实现在需要的页面手动连接websocket
    // main.js 在插件配置里添加connectManually属性    // 开启手动调用 connect() 连接服务器    connectManually: true复制代码
  • 在需要的地方进行手动连接
    // 使用this.$connect(URL)方法    this.$connect(`${base.lkWebSocket}/${localStorage.getItem("userID")}`);复制代码
  • 页面销毁时关闭连接
    // beforeDestroy生命周期中调用$disconnect方法    beforeDestroy() {      // 页面销毁时,断开连接      console.log("页面销毁,断开websocket连接");      this.$disconnect();    },复制代码

消息发送注意事项

  • this.$socket.sendObj()函数
  // 开启json传输时使用sendObj进行消息发送  this.$socket.sendObj({  });    // 为开启json传输时,使用send()函数进行发送  this.$socket.send(""); 复制代码

设置心跳消息

  • 在vuex的配置文件中添加定时器,向服务端推送消息
// src/store/index.jsstate{    socket{        // 心跳消息发送时间        heartBeatInterval: 30000,        // 心跳定时器        heartBeatTimer: 0    }}mutations:{    // 连接打开    SOCKET_ONOPEN (state, event)  {      Vue.prototype.$socket = event.currentTarget;      state.socket.isConnected = true;      // 连接成功时启动定时发送心跳消息,避免被服务器断开连接      state.socket.heartBeatTimer = setInterval(() => {        const message = "心跳消息";        state.socket.isConnected && Vue.prototype.$socket.sendObj({"code":200,"msg":message});      }, state.socket.heartBeatInterval);    },    // 连接关闭    SOCKET_ONCLOSE (state, event)  {      state.socket.isConnected = false;      // 连接关闭时停掉心跳消息      clearInterval(state.socket.heartBeatTimer);      state.socket.heartBeatTimer = 0;      console.log('连接已断开: ' + new Date());      console.log(event);    },}复制代码

写在最后

  • 项目地址: https://github.com/likaia/chat-system
  • 文中如有错误,欢迎在评论区指正,如果这篇文章帮到了你,欢迎点赞和关注
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值