vue基于websocket实现智能聊天及吸附动画效果

作者:接着奏乐接着舞。 时间:2024-04-30 08:45:20 

前言:

发现这篇文章写的有点多,我总结一下整体思路:

首先这个功能市面上挺多的,我是参考了几家公司的功能实现,发现他们的整体功能实现和下面我的截图类似。

首先核心功能是基于websocket实现用户输入文字服务器根据用户输入返回数据渲染在页面上,而这个功能我不推荐直接使用原生,而是使用封装好的,就像文章里封装的socket.js,这个文件很简单就对外提供三个方法,一个是和后端通信连接,再一个是接收后端的数据,最后一个是发送数据给后端。

其次,我们需要一个聊天框,我使用的Jwchat插件,优点是功能比较全类似QQ聊天,使用方法也很简单,但是话说回来,这个插件的很多样式需要修改,尤其对于要做页面适配的项目,所以这个插件不是特别推荐,还有一个点就是他没有关闭按钮,做的比较粗糙,我是通过在生命周期中使用原生JS添加的关闭图标,然后再通过watch动态的选择要不要创建删除按钮。

最后说一下动画,其实就是一个聊天框,一个小框,通过点击使v-show绑定的变量来实现切换效果。这个吸附效果是我用CSS动画将原本的一个长方形框框翻转180度后在平移模拟吸附效果,其实正儿八经做的话需要计算页面宽度和元素位置计算出一个比例然后再设置一个动画效果,这个GitHub上还是有挺多的,注意的是很多实现都是移动端的,PC端用不了,是个坑。再一个动画就是打开关闭时的效果,使用的是elementUI自带的动画效果。

1.效果如下:

vue基于websocket实现智能聊天及吸附动画效果

2.主要功能:

2.1.基于websocket实现聊天功能,封装了一个socket.js文件

2.2使用Jwchat插件实现类似QQ、微信电脑端的功能

(其实并不是很好用,但考虑到后续可能会使用其功能就先用了)

2.3动画效果(如关闭打开时动画、吸附效果及其他效果)

3.实现步骤:

3.1.实现websocket聊天功能

首先封装了一个socket.js文件;需要主要的是将socket.js中URL修改成自己的

vue基于websocket实现智能聊天及吸附动画效果

封装的websocke暴露三个接口

  • sendSock用于发送数据,发给后端

  • createWebSocket用于创建连接、接收数据并进行处理

  • closeSock 用于关闭连接

3.2.在页面中的使用方法: 

第一步:导入文件

import { sendSock, createWebSocket, closeSock } from "@/api/socket";

第二步:初始化时建立websocket连接

created() {
   this.init();
   ......
 },
 methods: {
   init() {
     createWebSocket(this.global_callback);
     ......
   },

// websocket的回调函数,msg表示收到的消息
   global_callback(msg) {
     console.log("收到服务器信息:" + msg);
   },
 },

关闭连接

closeSock();

发送给后端的方法

sendSock(xxx)
var websock = null;
var global_callback = null;
var serverPort = "80"; // webSocket连接端口
var wsuri = "ws://" + window.location.hostname + ":" + serverPort;
function createWebSocket(callback) {
 if (websock == null || typeof websock !== WebSocket) {
   initWebSocket(callback);
 }
}
function initWebSocket(callback) {
 global_callback = callback;
 // 初始化websocket
 websock = new WebSocket(wsuri);
 websock.onmessage = function (e) {
   websocketonmessage(e);
 };
 websock.onclose = function (e) {
   websocketclose(e);
 };
 websock.onopen = function () {
   websocketOpen();
 };
 // 连接发生错误的回调方法
 websock.onerror = function () {
   console.log("WebSocket连接发生错误");
    //createWebSocket();啊,发现这样写会创建多个连接,加延时也不行
 };
}
// 实际调用的方法
function sendSock(agentData ) {
 if (websock.readyState === websock.OPEN) {
   // 若是ws开启状态
   websocketsend(agentData);
 } else if (websock.readyState === websock.CONNECTING) {
   // 若是 正在开启状态,则等待1s后重新调用
   setTimeout(function () {
     sendSock(agentData);
   }, 1000);
 } else {
   // 若未开启 ,则等待1s后重新调用
   setTimeout(function () {
     sendSock(agentData);
   }, 1000);
 }
}
function closeSock() {
 websock.close();
}
// 数据接收
function websocketonmessage(msg) {
 // console.log("收到数据:"+JSON.parse(e.data));
 // console.log("收到数据:"+msg);
 // global_callback(JSON.parse(msg.data));
 // 收到信息为Blob类型时
 let result = null;
 // debugger
 if (msg.data instanceof Blob) {
   const reader = new FileReader();
   reader.readAsText(msg.data, "UTF-8");
   reader.onload = (e) => {
     result = JSON.parse(reader.result);
     //console.log("websocket收到", result);
     global_callback(result);
   };
 } else {
   result = JSON.parse(msg.data);
   //console.log("websocket收到", result);
   global_callback(result);
 }
}
// 数据发送
function websocketsend(agentData) {
 console.log("发送数据:" + agentData);
 websock.send(agentData);
}
// 关闭
function websocketclose(e) {
 console.log("connection closed (" + e.code + ")");
}
function websocketOpen(e) {
 console.log("连接打开");
}
export { sendSock, createWebSocket, closeSock };

4.使用Jwchat插件实现类似QQ、微信电脑端的功能

vue基于websocket实现智能聊天及吸附动画效果

 4.1步骤

  安装依赖

npm i jwchat -S

  main.js 引入配置 

//element 必须引入
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
//聊天室-基于element
import Chat from 'jwchat';
Vue.use(Chat)

  组件中使用

<template>
 <div class="jwchat">
   <!--
     v-model输入框中的文字String-""
     taleList会话内容Array-[]
     toolConfig工具栏配置Object-{}
     widthJwChat界面框宽度string-750px
     heightJwChat界面框高度string-570px
     config组件配置Object-{}
     scrollType消息自动到低Stringscrollnoroll
     showRightBox显示右边内容Booleanfalsetrue
     winBarConfig多窗口配置
     quickList   自动匹配快捷回复
     @enter输入框点击就发送或者回车触发的事件输入的原始数据
     @clickTalk点击聊天框列中的用户和昵称触发事件当前对话数据
    -->
   <JwChat-index
     v-model="inputMsg"
     :taleList="taleList"
     :config="config"
     :showRightBox="true"
     scrollType="scroll"
     :winBarConfig="winBarConfig"
     :quickList="config.quickList"
     @enter="bindEnter"
     @clickTalk="talkEvent"
   >
     <!-- 窗口右边栏 -->
     <JwChat-rightbox :config="rightConfig" @click="rightClick" />
     <!-- 快捷回复 -->
     <!-- <JwChat-talk :Talelist="talk" :config="quickConfig" @event="bindTalk" /> -->
     <!-- 工具栏自定义插槽 -->
     <template slot="tools">
       <div style="width: 20rem; text-align: right" @click="toolEvent(12)">
         <JwChat-icon type="icon-lishi" title="自定义" />
       </div>
     </template>
   </JwChat-index>
 </div>
</template>

<script>
const img = "https://www.baidu.com/img/flexible/logo/pc/result.png";
const listData = [

{
   date: "2021/03/02 13:14:21",
   mine: false,
   name: "留恋人间不羡仙",
   img: "https://img0.baidu.com/it/u=3066115177,3339701526&fm=26&fmt=auto&gp=0.jpg",
   text: {
     system: {
       title: "在接入人工前,智能助手将为您首次应答。",
       subtitle: "猜您想问:",
       content: [
         {
           id: `system1`,
           text: "组件如何使用",
         },
         {
           id: `system2`,
           text: "组件参数在哪里查看",
         },
         {
           id: "system",
           text: "我可不可把组件用在商业",
         },
       ],
     },
   },
 },
];
function getListArr(size) {
 const listSize = listData.length;
 if (!size) {
   size = listSize;
 }
 let result = [];
 for (let i = 0; i < size; i++) {
   const item = listData[(Math.random() * listSize) >> 0];
   item.id = Math.random().toString(16).substr(-6);
   result.push(item);
 }
 return result;
}
export default {
 components: {},
 data() {
   return {
     // 输入框中的文字
     inputMsg: "",
     // 会话内容
     taleList: [],
     // 工具栏配置
     tool: {
       // show: ['file', 'history', 'img', ['文件1', '', '美图']],
       // showEmoji: false,
       callback: this.toolEvent,
     },
     // 组件配置
     config: {
       img: "https://img1.baidu.com/it/u=2109725846,3376113789&fm=26&fmt=auto&gp=0.jpg",
       name: "JwChat",
       dept: "最简单、最便捷",
       callback: this.bindCover,
       historyConfig: {
         show: true,
         tip: "滚动到顶时候显示的提示",
         callback: this.bindLoadHistory,
       },
       // 自动匹配快捷回复
       quickList: [

{ text: "外面的烟花奋力的燃着,屋里的人激情的说着情话", id: 10 },
         { text: "假如你是云,我就是雨,一生相伴,风风雨雨;", id: 11 },
         {
           text: "即使泪水在眼中打转,我依旧可以笑的很美,这是你学不来的坚强。",
           id: 12,
         },
         {
           text: " 因为不知来生来世会不会遇到你,所以今生今世我会加倍爱你。",
           id: 13,
         },
       ],
     },

};
 },
 methods: {
   // 切换用户窗口,加载对应的历史记录
   bindWinBar(play = {}) {
     const { type, data = {} } = play;
     console.log(play);
     if (type === "winBar") {
       const { id, dept, name, img } = data;
       this.config = { ...this.config, id, dept, name, img };
       this.winBarConfig.active = id;
       if (id === "win00") {
         this.taleList = getListArr();
       } else this.taleList = getListArr((Math.random() * 4) >> 0);
     }
     if (type === "winBtn") {
       const { target: { id } = {} } = data;
       const { list } = this.winBarConfig;
       this.winBarConfig.list = list.reduce((p, i) => {
         if (id != i.id) p.push(i);
         return p;
       }, []);
     }
   },
   // 点击聊天框列中的用户和昵称触发事件
   talkEvent(play) {
     console.log(play);
   },
   // 输入框点击就发送或者回车触发的事件
   bindEnter(e) {
     console.log(e);
     const msg = this.inputMsg;
     if (!msg) return;
     const msgObj = {
       date: "2020/05/20 23:19:07",
       text: { text: msg },
       mine: true,
       name: "JwChat",
       img: "https://img1.baidu.com/it/u=31094377,222380373&fm=26&fmt=auto&gp=0.jpg",
     };
     this.taleList.push(msgObj);
   },

/**
    * @description: 点击加载更多的回调函数
    * @param {*}
    * @return {*}
    */
   bindLoadHistory() {
     const history = new Array(3).fill().map((i, j) => {
       return {
         date: "2020/05/20 23:19:07",
         text: { text: j + new Date() },
         mine: false,
         name: "JwChat",
         img: "https://img1.baidu.com/it/u=31094377,222380373&fm=26&fmt=auto&gp=0.jpg",
       };
     });
     let list = history.concat(this.list);
     this.taleList = list;
     console.log("加载历史", list, history);
   },
   /**
    * @description:
    * @param {*} type 当前点击的按钮
    * @param {*} plyload 附加文件或者需要处理的数据
    * @return {*}
    */
   toolEvent(type, plyload) {
     console.log("tools", type, plyload);
   },
   bindCover(event) {
     console.log("header", event);
   },
   rightClick(type) {
     console.log("rigth", type);
   },
 },
 mounted() {
   this.taleList = getListArr();
 },
};
</script>

<style>
.jwchat {
 height: 100vh;
 font-family: Avenir, Helvetica, Arial, sans-serif;
 -webkit-font-smoothing: antialiased;
 -moz-osx-font-smoothing: grayscale;
 text-align: center;
 color: #2c3e50;
 margin-top: 60px;
}
</style>

5.动画效果

吸附效果

使用v-show绑定变量控制显示隐藏

// 吸附效果
   xiFu () {
     setTimeout(() => {
       //10秒后自动隐藏小空间转为吸附效果
       this.isMouse = false
     }, 5000)
   },
@keyframes move {
 0% {
   transform: translateX(0px) rotateY(20deg);
 }
 100% {
   transform: translateX(1.0417rem) rotateY(180deg);
 }
}

.cssDongHua {
 animation: move 2s linear 1s 1 alternate forwards;
}
//template
:class="isMouse ? '' : 'cssDongHua'"
       @click="isOpen = !isOpen"
       v-show="!isOpen"
       @mouseenter="isMouse = true"

来源:https://blog.csdn.net/wanghaoyingand/article/details/125659423

标签:vue,websocket,聊天,吸附动画
0
投稿

猜你喜欢

  • 详解go中的引用类型

    2023-08-28 06:02:31
  • Python实现粒子群算法的示例

    2021-06-08 17:34:02
  • python设置代理和添加镜像源的方法

    2022-12-03 10:26:39
  • C#使用ODBC与OLEDB连接数据库的方法示例

    2024-01-12 17:41:41
  • python tornado使用流生成图片的例子

    2023-08-24 07:07:20
  • javascript 操作文件 实现方法小结

    2024-04-22 12:48:27
  • 对Python的zip函数妙用,旋转矩阵详解

    2023-06-09 12:42:45
  • 如何把数据库记录显示到列表框里去?

    2009-11-06 13:48:00
  • Pycharm 2020.1 版配置优化的详细教程

    2023-06-30 23:11:55
  • T-SQL 查询语句的执行顺序解析

    2024-01-14 08:00:00
  • es6函数之严格模式用法实例分析

    2023-08-09 06:15:40
  • Spring Security使用数据库登录认证授权

    2024-01-23 05:26:59
  • Python Pandas 获取列匹配特定值的行的索引问题

    2023-11-01 06:37:42
  • 在脚本中单独使用django的ORM模型详解

    2021-03-09 05:17:26
  • Pytorch中的广播机制详解(Broadcast)

    2022-11-17 05:22:51
  • 详解Golang语言HTTP客户端实践

    2023-09-17 13:52:07
  • 详解python基础之while循环及if判断

    2023-01-14 20:54:39
  • PHP的mysqli_rollback()函数讲解

    2023-06-12 08:58:03
  • python之文件读取一行一行的方法

    2022-04-09 20:21:19
  • vscode常用插件整理汇总

    2023-11-21 10:48:59
  • asp之家 网络编程 m.aspxhome.com