vue之websocket聊天功能实现

2023-11-05

一、首先配置全局websocket

创建webSocket.js:

// global.js
export default {
  ws: {},
  setWs: function(newWs) {
      this.ws = newWs
  }
}

main.js引入:

import webSocket from './utils/webSocket.js'
Vue.prototype.$webSocket = webSocket

在其他页面使用:

this.$webSocket.ws

二、App.vue监听websocket

 created() {
        this.initWebsocket();
    }
 methods: {
initWebsocket() {
            let that = this
            if ('WebSocket' in window) {
                that.ws = new WebSocket('ws://127.0.0.1:30000/ws')
                that.$webSocket.setWs(that.ws)
                that.ws.onopen = function () {
                    setTimeout(() => {
                        that.queryMessage()
                    }, 500)
                }
                //that.onopen(); 这个地方未定义是会报错,所以我写成了  that.ws.onopen = function() {console.log('开始连接')};
                that.ws.onclose = function () {
                    // 关闭 websocket
                    console.log('连接已关闭...')
                    setTimeout(() => {
                        that.initWebsocket()
                    }, 2000)
                }
            } else {
                // 浏览器不支持 WebSocket
                console.log('您的浏览器不支持 WebSocket!')
            }
        },
        queryMessage() {
            let that = this;
            let customerList = this.$store.state.permission.customerList;
            let expertList = this.$store.state.permission.expertList;
            for (let index = 0; index < customerList.length; index++) {
                let msg = {
                    type: "login",
                    uid: customerList[index].id
                };
                if (that.$webSocket.ws && that.$webSocket.ws.readyState == 1) {
                    that.$webSocket.ws.send(JSON.stringify(msg));
                }
            }
            for (let index = 0; index < expertList.length; index++) {
                let msg = {
                    type: "login",
                    uid: expertList[index].id
                };
                if (that.$webSocket.ws && that.$webSocket.ws.readyState == 1) {
                    that.$webSocket.ws.send(JSON.stringify(msg));
                }
            }
            that.$webSocket.ws.onmessage = function (res) {
                let jsonData = JSON.parse(res.data);
                let data = jsonData.data;
                //新推过来条数
                let customerList = that.$store.state.permission.customerList;
                for (let index = 0; index < customerList.length; index++) {
                    if(jsonData.uid == customerList[index].id){
                        axios.post("获取总条数接口",{uid:customerList[index].id}).then(res=>{
                            if(res.data.success == true){
                                if(customerList[index].msgNum == null){
                                    customerList[index].msgNum=0;
                                    customerList[index].msgNum+=res.data.data;
                                }
                            }
                        })
                        if (data.type == "newConv") {
                            if (customerList[index].id != data.send_uid) {
                                customerList[index].msgNum++;
                                break;
                            }
                        } else if (data.type == "newMsg") {
                            if (customerList[index].id != data.send_uid) {
                                customerList[index].msgNum++;
                                break;
                            }
                        }
                    }
                }
                that.$store.state.permission.customerList = customerList;
                //新推过来条数
                let expertList = that.$store.state.permission.expertList;
                for (let index = 0; index < expertList.length; index++) {
                    if(jsonData.uid == expertList[index].id){
                        axios.post("获取总条数接口",{uid:expertList[index].id}).then(res=>{
                            if(res.data.success == true){
                                if(expertList[index].msgNum == null){
                                    expertList[index].msgNum=0;
                                    expertList[index].msgNum+=res.data.data;
                                }
                            }
                        })
                        if (data.type == "newConv") {
                            if (expertList[index].id != data.send_uid) {
                                expertList[index].msgNum++;
                                break;
                            }
                        } else if (data.type == "newMsg") {
                            if (expertList[index].id != data.send_uid) {
                                expertList[index].msgNum++;
                                break;
                            }
                        }
                    }
                }
                that.$store.state.permission.expertList = expertList;
            };
        }
}
}

 三、聊天界面

<template>
  <div class="ContactWrap" v-if="uid != 0">
    <div class="Contact">
      <div class="ContactSide">
        <!-- <div class="ContactSide-tip"></div> -->
        <div >
            <div v-for="(item,index) in userList" :key="index" >
                <div class="ContactItem" @click="chooseUser(item)" :class="{ChooseItem : item.uid == chooseId}">
                    <img class="UserAvator" :src="item.avatar"  />
                    <div class="UserContent">
                    <div class="UserMsg">
                        <span class="UserName" style="padding-left:5px;">{{item.nickname}}</span>
                        <span class="MsgTime">{{item.last_msg_time.split(' ')[0]}}</span>
                    </div>
                    <div class="UserSnippet" style="padding-top:8px;" :title="title">{{customMethod(item.msg_type,item.msg_content)}}</div>
                    <span v-if="item.unreadCount != 0" style="float:right; display:inline-block; border-radius:5px 5px 5px 5px;line-height: 90px;height:15px;margin-left:100px;margin-top:-15px;color:rgb(255 255 255);font-size:10px;background-color:#cccccc;display:flex;justify-content:center;align-items:center;">{{item.unreadCount}}</span>
                    </div>
                </div>
            </div>
        </div>
      </div>
      <div class="ContactBox">
        <div class="ContactBox-header" style="font-size:18px;">{{titename}}</div>
        <div class="MessageBox" ref="MessageBox">
          <div
            v-for="(item,index) in chatList"
            :key="index"
            class="Message"
            :style="item.send_uid == uid?'flex-direction:row-reverse':''"
          >
            <!-- <div class="UserHead"> -->
            <img :src="item.send_uid == uid? pcimg:duifangimg" class="UserAvator" />
            <!-- </div> -->
            <div class="UserMsg" :class="item.send_uid == uid?'RightMessage':'LeftMessage'">
              <span v-if="item.msg_type == 1" :style="item.send_uid == uid?' float: right;':''">{{item.msg_content}}</span>
              <span
                        :style="item.send_uid == uid?' float: right;':''"
                        v-if=" item.msg_type == 2 "
                    >
                        <video
                            style="width: 160px"
                            controls="controls"
                            :src="item.msg_content"
                            alt=""
                            srcset=""
                        ></video>
                    </span>
                <span
                    :style="item.send_uid == uid?' float: right;':''"
                    v-if="item.msg_type == 4 "
                >
                     <img
                          v-image-preview
                          :src="item.msg_content"
                          alt=""
                          srcset=""
                          style="
                              vertical-align: text-top;
                              display: inline-block;
                              width: 40px;
                              height:40px
                          "
                      />
                </span>
                <span
                    :style="item.send_uid == uid?' float: right;':''"
                    v-if="item.msg_type == 3 "
                >
                     <audio
                        style="width: 200px"
                        controls="controls"
                        :src="item.msg_content"
                        alt=""
                        srcset=""
                    ></audio>
                </span>
            </div>
          </div>
        </div>
        <!-- 输入框 -->
        <div class="InputBox">
          <div v-if="titename != ''">
            <textarea v-model="msg" style="resize:none" class="InputTextarea" rows="3" ></textarea>
            <div class="InputBox-footer">
              <!-- <div class="FooterDesc">按Enter键发送</div> -->
              <button class="sendButton"  @click="sendmsg($event)">发送</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import util from "@/utils/index.js";
import axios from "axios";
export default {
  name: "Chat",
  components: {},
  data() {
    return {
      uid: 0,
      ws: null,
      msg: "", //聊天信息
      chatList: [
        // {
        //   id: 14,
        //   content: "哈哈哈",
        //   avaUrl:
        //     "https://pic4.zhimg.com/v2-a12b2d609fa2d5d16c10ea069419f3c3_xs.jpg"
        // },
        // {
        //   id: 1,
        //   content: "嘿嘿嘿",
        //   avaUrl:
        //     "https://pic4.zhimg.com/v2-a12b2d609fa2d5d16c10ea069419f3c3_xs.jpg"
        // },
      ], //聊天记录
      userList: [
        // {
        //   uid:1,
        //   username: "test1",
        //   content: "美美哒",
        //   time: "6-22",
        //   avaUrl:
        //     "https://pic4.zhimg.com/v2-a12b2d609fa2d5d16c10ea069419f3c3_xs.jpg"
        // },
        // {
        //      uid:2,
        //   username: "test2",
        //   content: "活好每一天",
        //   time: "6-22",
        //   avaUrl:
        //     "https://pic4.zhimg.com/v2-a12b2d609fa2d5d16c10ea069419f3c3_xs.jpg"
        // },
      ],
      chooseId:0,
      titename:"",
      title: "",
      conv_id:"",
      duifangimg:"",
    };
  },
  props:['fuid','pcimg'],
  mounted() {
    this.uid = this.fuid;//可以自己写个假数据
    setTimeout(() => {
      this.getChatList();
    }, 300);
    //this.initWebsocket();
  },
  watch:{     //监听value的变化,进行相应的操做便可
    fuid: function(a,b){     //a是value的新值,b是旧值
      this.uid = this.fuid;
      this.chatList =[]
      this.getChatList();
    }
  },
  methods: {
    //发送信息
    sendmsg(event) {
      event.preventDefault()
      let msg = {"type":"send","send_id":this.uid,"receive_id":this.chooseId,"msg_type":"1","content":this.msg};
      if (this.$webSocket.ws && this.$webSocket.ws.readyState == 1) {
          this.$webSocket.ws.send(JSON.stringify(msg));
      }
      setTimeout(() => {
          this.getMsgList(this.conv_id);
      }, 500)
      this.msg = "";
    },
    //滚动条滚动到底部
    scrollBottm() {
      let el = this.$refs["MessageBox"];
      el.scrollTop = el.scrollHeight;
    },
    //选择联系人
    chooseUser(user){
        this.chooseId = user.uid;
        this.titename = user.nickname;
        this.getMsgList(user.conv_id);
    },
    //获取聊天列表
    getChatList(){
       axios.post("聊天列表接口",{uid:this.uid}).then(res=>{
           if(res.data.success == true){
               this.userList = res.data.data;
               if(this.userList.length>0){
                  this.chooseId = this.userList[0].uid;
                  this.titename = this.userList[0].nickname;
                  this.conv_id = this.userList[0].conv_id;
                  this.getMsgList(this.userList[0].conv_id);
                  this.duifangimg = this.userList[0].avatar;
               }else{
                  this.chooseId = '';
                  this.titename = '';
               }
               
           }
       })
    },
    //获取聊天记录
    getMsgList(chooseId){
      axios.post("聊天记录接口",{cid:chooseId,uid:this.uid,pagesize:'10'}).then(res=>{
           if(res.data.success == true){
                this.chatList = res.data.data;
                let msgNums = 0;
                for(let i=0;i<this.userList.length;i++){
                    if(this.userList[i].conv_id == chooseId){
                        msgNums = this.userList[i].unreadCount;
                        this.userList[i].unreadCount = 0;
                        this.$emit('getInitData',this.fuid,msgNums);
                    }
                }
                setTimeout(() => {
                  this.scrollBottm();
                }, 50);
           }
       })
    },
    //隐藏字符串
    customMethod(type,msg){
      if(type == '1'){
        if(msg.length<10){
          return msg;
        }else{
          this.title=msg.substring(0,10)+'...';
          return msg.substring(0,10)+'...';
        }
      }else {
        this.title='媒体消息';
        return '[媒体消息]';
      }
    },
    //重新计算未读消息数
    getUnreadNum(msgNums){
      //把未读消息数清空
      // for (let index = 0; index < this.$store.state.permission.customerList.length; index++) {
      //     if(this.fuid == this.$store.state.permission.customerList[index].id){
      //       if(this.$store.state.permission.customerList[index].msgNum != null && this.$store.state.permission.customerList[index].msgNum >= msgNums){
      //         this.$store.state.permission.customerList[index].msgNum = this.$store.state.permission.customerList[index].msgNum - msgNums;
      //       }else{
      //         this.$store.state.permission.customerList[index].msgNum = 0;
      //       }
      //     }
      // }
      // for (let index = 0; index < this.$store.state.permission.expertList.length; index++) {
      //     if(this.fuid == this.$store.state.permission.expertList[index].id){
      //       if(this.$store.state.permission.expertList[index].msgNum != null && this.$store.state.permission.expertList[index].msgNum >= msgNums){
      //         this.$store.state.permission.expertList[index].msgNum = this.$store.state.permission.expertList[index].msgNum - msgNums;
      //       }else{
      //         this.$store.state.permission.expertList[index].msgNum = 0;
      //       }
      //     }
      // }
     
    } 
    }
  }

</script>
<style lang="scss" scoped>
.Contact {
  height: 704px;
  width: 100%;
  background-color: #fff;
  border: 1px solid #ebebeb;
  box-shadow: 0 0 4px 0 rgba(26, 26, 26, 0.1);
  border-radius: 3px;
  display: flex;
  //联系人
  .ContactSide {
    width: 500px;
    height: 100%;
    border-right: 1px solid #ebebeb;
    .ContactSide-tip {
      height: 60px;
      line-height: 40px;
      font-weight: 600;
      padding: 0 30px;
      border-bottom: 1px solid #ebebeb;
    }
  }
  .ContactItem {
    padding: 12px 20px 12px 29px;
    cursor: pointer;
    display: flex;
    border-bottom: 1px solid #f7f8fa;
    .UserContent {
      flex: 1;
      .UserMsg {
        display: flex;
        align-items: center;
        justify-content: space-between;
        .UserName {
          font-size: 15px;
          columns: #444444;
          font-weight: 600;
        }
        .MsgTime {
          font-size: 12px;
          color: #999999;
          float: right;
        }
      }
    }
  }
  .ChooseItem{
    background: #f5f4f4;
 }
  .UserAvator {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    margin-right: 10px;
  }
  .ContactBox {
    width: 100%;
    &-header {
      background: #fafafa;
      font-size: 15px;
    //   margin: 0 14px;
    //   height: 20px;
      padding-bottom: 21px;
      padding-top: 22px;
      border-bottom: 1px solid #ebebeb;
      font-weight: 600;
      text-align: center;
    }
    //聊天框
    .MessageBox {
      height: 470px;
      overflow: scroll;
      .Message {
        display: flex;
        margin: 20px;
        .UserMsg {
          max-width: 388px;
          border-radius: 8px;
          padding: 6px 12px;
          font-size: 14px;
          position: relative;
          margin: 0 8px;
          text-align: left;
          white-space: pre-wrap;
          word-break: break-all;
        }
        .LeftMessage {
          background-color: #f6f6f6;
          color: #444;
          &::after {
            content: "";
            position: absolute;
            width: 8px;
            height: 8px;
            left: -4px;
            top: 14px;
            background: #f6f6f6;
            -webkit-transform: rotate(45deg);
            transform: rotate(45deg);
          }
        }
        .RightMessage {
          background-color: #0084ff;
          color: #fff;
          &::after {
            content: "";
            position: absolute;
            width: 8px;
            height: 8px;
            right: -4px;
            top: 14px;
            background: #0084ff;
            -webkit-transform: rotate(45deg);
            transform: rotate(45deg);
          }
        }
      }
    }
    //输入框
    .InputBox {
      padding: 0 10px;
      border-top: 1px solid #ebebeb;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      height: 168px;
      background: #fff;
      z-index: 10;
      .InputTextarea {
        margin-top: 20px;
        width: 100%;
        border: none;
        font-size: 14px;
        flex: 1;
        height:90px;
      }
      &-footer {
        display: flex;
        align-items: center;
        justify-content: flex-end;
        height: 40px;
        .FooterDesc {
          font-size: 14px;
          color: #bfbfbf;
          padding-right: 10px;
        }
        .sendButton {
          color: #fff;
          background-color: #0084ff;
          border-radius: 6px;
          width: 72px;
          height: 32px;
          font-size: 13px;
          line-height: 32px;
          text-align: center;
        }
      }
    }
  }
}
 
</style>

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue之websocket聊天功能实现 的相关文章

随机推荐

  • 做接口测试如何上次文件

    在日常工作中 经常有上传文件功能的测试场景 因此 本文介绍两种主流编写上传文件接口测试脚本的方法 首先 要知道文件上传的一般原理 客户端根据文件路径读取文件内容 将文件内容转换成二进制文件流的格式传输给服务端 而服务端接受客户端传过来的二进
  • 构建ubuntu根文件系统

    构建ubuntu根文件系统 象棋小子 1048272975 Ubuntu是一个广泛应用于个人电脑 云计算 以及智能物联网设备的开源操作系统 针对智能物联网 Ubuntu提供了一套更加安全 轻量级 专为智能物联网订制的开源操作系统Ubuntu
  • 前后端交互的api

    api是application interface应用接口 通过原生ajax或者jQuery或者axios 发送请求 连接后端的核心纽带 可以说也是一种革命 因为之前都是混编 html代码与后端语言杂合在一起 原码即是运行的代码 不加以修饰
  • 类加载器 & 打破双亲委派机制(个人总结)

    声明 1 本文为我的个人复习总结 并非那种从零基础开始普及知识 内容详细全面 言辞官方的文章 2 由于是个人总结 所以用最精简的话语来写文章 3 若有错误不当之处 请指出 类加载器 启动类加载器 加载JAVA HOME lib下的核心类 扩
  • HJ68 成绩排序【python3】

    题目描述 给定一些同学的信息 名字 成绩 序列 请你将他们的信息按照成绩从高到低或从低到高的排列 相同成绩 都按先录入排列在前的规则处理 例示 jack 70 peter 96 Tom 70 smith 67 从高到低 成绩 peter 9
  • Linux下,qt5中使用Qt Multimedia编译时遇到报错

    遇到defaultServiceProvider requestService no service found for org qt project qt mediaplayer 错误 解决方法 在Linux中 sudo apt get
  • 商城前台项目:商品三级分类功能实现

    项目效果 实现代码 components Category index vue div h2 class all 全部商品分类 h2 div
  • Mac笔记本Xcode打开不了文件和打开文件看不到新添加的文件的解决办法

    第一次使用xcode碰见了以下问题 创建完项目之后 在文件外面将自己想要的文件复制进去文件后 重新打开xcode发现并不显示文件 xcode不能打开非Xcode创建的文件夹 解决办法 用xcode创建项目后 需要在左下角添加文件进来才能看到
  • ssh框架hibernate 查询方式和查询功能优化

    Hibernate框架的查询方式 1 唯一标识OID的检索方式 session get 对象 class OID 2 对象的导航的方式 3 HQL的检索方式 Hibernate Query Language Hibernate的查询语言 4
  • JavaEE——SmartTomcat的使用教程与常见错误

    SmartTomcat 上一篇博客讲到 使用tomcat创建servlet项目有以下几个步骤 创建maven项目 引入servlet依赖 创建目录 编写代码 打包成war包 拷贝到webapps目录下 运行tomcat 验证程序 可以看到步
  • 设计模式(4)-原型模式(Prototype Pattern)

    所谓原型模式就是从原型实例去复制克隆出新的实例 而绝不是去从类去实例化 就好比打飞机的游戏 我们操作的主角飞机只有一架 可以用单例模式去实现 而敌机好多都是一样的 如果每出一个敌机我们就去new一个敌机的对象 一下来个三十个 就去new三十
  • 【傅里叶级数与傅里叶变换】数学推导——1、基础知识点回顾及[Part1:三角函数的正交性]介绍

    文章内容来自DR CAN关于傅里叶变换的视频 本篇文章提供了一些基础知识点 比如三角函数常用的导数 三角函数换算公式等 文章全部链接 基础知识点 Part1 三角函数系的正交性 Part2 T 2 的周期函数的傅里叶级数展开 Part3 周
  • 42-Golang中的单元测试

    Golang中的单元测试 需求 传统方法 基本介绍 单元测试快速入门总结 综合案例 需求 在工作中 我们会遇到这样的情况 就是去确认一个函数 或者一个模块的结果是否正确 传统方法 在main函数中 调用addUpper函数 看看实际输出的记
  • 内网能ping通telnet 通,不能访问解决

    内网能PING通TELNET通不能访问解决 遇到一个离奇故障 内网 两个主机在同一IP段内 能互相PING通 TELNET对方的WEB服务器端口 通 但用IE访问时不能 显示HTTP400 这明显是客户端系统的问题啊 但如何解决呢 我强烈怀
  • LeetCode 1233. 删除子文件夹(C++)

    思路 1 首先能想到这种判断字符串前缀的题目可以使用前缀树 2 对字符串字典序排序 那么就能满足 一个子文件夹的左边要么是同父文件夹的子文件夹 要么就是他的父文件夹 同时 第一个文件夹一定是父文件夹 那么就可以建立一个父文件夹地址 每次便利
  • vs2019 中文离线安装包下载,类似ISO,不用联网安装vs2019企业版

    vs2019 中文离线安装包下载 类似ISO 不用联网安装vs2019企业版 前言 我们现在微软官方网站下载的安装包一般也就1 2兆 运行这个小安装包的程序时 才真正在网站上下载vs2019 目前的vs2019企业版 专业版 社区版都要20
  • FISCO BCOS 2.9.1 从0部署到简单使用的CRUD接口

    FISCO BCOS 2 9 1 从0部署到简单使用CRUD接口 文章目录 FISCO BCOS 2 9 1 从0部署到简单使用CRUD接口 前言 1 部署fisoc bcos 2 9 1环境 1 1 安装centos依赖 1 2 创建fi
  • Hibernate+spring缓存机制配置

    在applicationContext xml文件中添加以下代码
  • 关于Tp中图片路径的问题

    图片一般放在Public 目录下 在模板文件中引用图片时 src PUBLIC 图片Public 下面的路径 注意在linux下面要区分大小写 windows是不用区分也能识别的 部署服务器上后要严格区分大小写
  • vue之websocket聊天功能实现

    一 首先配置全局websocket 创建webSocket js global js export default ws setWs function newWs this ws newWs main js引入 import webSock