当前位置:   article > 正文

vue之websocket聊天功能实现_vue实现websocket对话

vue实现websocket对话

一、首先配置全局websocket

创建webSocket.js:

  1. // global.js
  2. export default {
  3. ws: {},
  4. setWs: function(newWs) {
  5. this.ws = newWs
  6. }
  7. }

main.js引入:

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

在其他页面使用:

this.$webSocket.ws

二、App.vue监听websocket

  1. created() {
  2. this.initWebsocket();
  3. }
  4. methods: {
  5. initWebsocket() {
  6. let that = this
  7. if ('WebSocket' in window) {
  8. that.ws = new WebSocket('ws://127.0.0.1:30000/ws')
  9. that.$webSocket.setWs(that.ws)
  10. that.ws.onopen = function () {
  11. setTimeout(() => {
  12. that.queryMessage()
  13. }, 500)
  14. }
  15. //that.onopen(); 这个地方未定义是会报错,所以我写成了 that.ws.onopen = function() {console.log('开始连接')};
  16. that.ws.onclose = function () {
  17. // 关闭 websocket
  18. console.log('连接已关闭...')
  19. setTimeout(() => {
  20. that.initWebsocket()
  21. }, 2000)
  22. }
  23. } else {
  24. // 浏览器不支持 WebSocket
  25. console.log('您的浏览器不支持 WebSocket!')
  26. }
  27. },
  28. queryMessage() {
  29. let that = this;
  30. let customerList = this.$store.state.permission.customerList;
  31. let expertList = this.$store.state.permission.expertList;
  32. for (let index = 0; index < customerList.length; index++) {
  33. let msg = {
  34. type: "login",
  35. uid: customerList[index].id
  36. };
  37. if (that.$webSocket.ws && that.$webSocket.ws.readyState == 1) {
  38. that.$webSocket.ws.send(JSON.stringify(msg));
  39. }
  40. }
  41. for (let index = 0; index < expertList.length; index++) {
  42. let msg = {
  43. type: "login",
  44. uid: expertList[index].id
  45. };
  46. if (that.$webSocket.ws && that.$webSocket.ws.readyState == 1) {
  47. that.$webSocket.ws.send(JSON.stringify(msg));
  48. }
  49. }
  50. that.$webSocket.ws.onmessage = function (res) {
  51. let jsonData = JSON.parse(res.data);
  52. let data = jsonData.data;
  53. //新推过来条数
  54. let customerList = that.$store.state.permission.customerList;
  55. for (let index = 0; index < customerList.length; index++) {
  56. if(jsonData.uid == customerList[index].id){
  57. axios.post("获取总条数接口",{uid:customerList[index].id}).then(res=>{
  58. if(res.data.success == true){
  59. if(customerList[index].msgNum == null){
  60. customerList[index].msgNum=0;
  61. customerList[index].msgNum+=res.data.data;
  62. }
  63. }
  64. })
  65. if (data.type == "newConv") {
  66. if (customerList[index].id != data.send_uid) {
  67. customerList[index].msgNum++;
  68. break;
  69. }
  70. } else if (data.type == "newMsg") {
  71. if (customerList[index].id != data.send_uid) {
  72. customerList[index].msgNum++;
  73. break;
  74. }
  75. }
  76. }
  77. }
  78. that.$store.state.permission.customerList = customerList;
  79. //新推过来条数
  80. let expertList = that.$store.state.permission.expertList;
  81. for (let index = 0; index < expertList.length; index++) {
  82. if(jsonData.uid == expertList[index].id){
  83. axios.post("获取总条数接口",{uid:expertList[index].id}).then(res=>{
  84. if(res.data.success == true){
  85. if(expertList[index].msgNum == null){
  86. expertList[index].msgNum=0;
  87. expertList[index].msgNum+=res.data.data;
  88. }
  89. }
  90. })
  91. if (data.type == "newConv") {
  92. if (expertList[index].id != data.send_uid) {
  93. expertList[index].msgNum++;
  94. break;
  95. }
  96. } else if (data.type == "newMsg") {
  97. if (expertList[index].id != data.send_uid) {
  98. expertList[index].msgNum++;
  99. break;
  100. }
  101. }
  102. }
  103. }
  104. that.$store.state.permission.expertList = expertList;
  105. };
  106. }
  107. }
  108. }

 三、聊天界面

  1. <template>
  2. <div class="ContactWrap" v-if="uid != 0">
  3. <div class="Contact">
  4. <div class="ContactSide">
  5. <!-- <div class="ContactSide-tip"></div> -->
  6. <div >
  7. <div v-for="(item,index) in userList" :key="index" >
  8. <div class="ContactItem" @click="chooseUser(item)" :class="{ChooseItem : item.uid == chooseId}">
  9. <img class="UserAvator" :src="item.avatar" />
  10. <div class="UserContent">
  11. <div class="UserMsg">
  12. <span class="UserName" style="padding-left:5px;">{{item.nickname}}</span>
  13. <span class="MsgTime">{{item.last_msg_time.split(' ')[0]}}</span>
  14. </div>
  15. <div class="UserSnippet" style="padding-top:8px;" :title="title">{{customMethod(item.msg_type,item.msg_content)}}</div>
  16. <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>
  17. </div>
  18. </div>
  19. </div>
  20. </div>
  21. </div>
  22. <div class="ContactBox">
  23. <div class="ContactBox-header" style="font-size:18px;">{{titename}}</div>
  24. <div class="MessageBox" ref="MessageBox">
  25. <div
  26. v-for="(item,index) in chatList"
  27. :key="index"
  28. class="Message"
  29. :style="item.send_uid == uid?'flex-direction:row-reverse':''"
  30. >
  31. <!-- <div class="UserHead"> -->
  32. <img :src="item.send_uid == uid? pcimg:duifangimg" class="UserAvator" />
  33. <!-- </div> -->
  34. <div class="UserMsg" :class="item.send_uid == uid?'RightMessage':'LeftMessage'">
  35. <span v-if="item.msg_type == 1" :style="item.send_uid == uid?' float: right;':''">{{item.msg_content}}</span>
  36. <span
  37. :style="item.send_uid == uid?' float: right;':''"
  38. v-if=" item.msg_type == 2 "
  39. >
  40. <video
  41. style="width: 160px"
  42. controls="controls"
  43. :src="item.msg_content"
  44. alt=""
  45. srcset=""
  46. ></video>
  47. </span>
  48. <span
  49. :style="item.send_uid == uid?' float: right;':''"
  50. v-if="item.msg_type == 4 "
  51. >
  52. <img
  53. v-image-preview
  54. :src="item.msg_content"
  55. alt=""
  56. srcset=""
  57. style="
  58. vertical-align: text-top;
  59. display: inline-block;
  60. width: 40px;
  61. height:40px
  62. "
  63. />
  64. </span>
  65. <span
  66. :style="item.send_uid == uid?' float: right;':''"
  67. v-if="item.msg_type == 3 "
  68. >
  69. <audio
  70. style="width: 200px"
  71. controls="controls"
  72. :src="item.msg_content"
  73. alt=""
  74. srcset=""
  75. ></audio>
  76. </span>
  77. </div>
  78. </div>
  79. </div>
  80. <!-- 输入框 -->
  81. <div class="InputBox">
  82. <div v-if="titename != ''">
  83. <textarea v-model="msg" style="resize:none" class="InputTextarea" rows="3" ></textarea>
  84. <div class="InputBox-footer">
  85. <!-- <div class="FooterDesc">按Enter键发送</div> -->
  86. <button class="sendButton" @click="sendmsg($event)">发送</button>
  87. </div>
  88. </div>
  89. </div>
  90. </div>
  91. </div>
  92. </div>
  93. </template>
  94. <script>
  95. import util from "@/utils/index.js";
  96. import axios from "axios";
  97. export default {
  98. name: "Chat",
  99. components: {},
  100. data() {
  101. return {
  102. uid: 0,
  103. ws: null,
  104. msg: "", //聊天信息
  105. chatList: [
  106. // {
  107. // id: 14,
  108. // content: "哈哈哈",
  109. // avaUrl:
  110. // "https://pic4.zhimg.com/v2-a12b2d609fa2d5d16c10ea069419f3c3_xs.jpg"
  111. // },
  112. // {
  113. // id: 1,
  114. // content: "嘿嘿嘿",
  115. // avaUrl:
  116. // "https://pic4.zhimg.com/v2-a12b2d609fa2d5d16c10ea069419f3c3_xs.jpg"
  117. // },
  118. ], //聊天记录
  119. userList: [
  120. // {
  121. // uid:1,
  122. // username: "test1",
  123. // content: "美美哒",
  124. // time: "6-22",
  125. // avaUrl:
  126. // "https://pic4.zhimg.com/v2-a12b2d609fa2d5d16c10ea069419f3c3_xs.jpg"
  127. // },
  128. // {
  129. // uid:2,
  130. // username: "test2",
  131. // content: "活好每一天",
  132. // time: "6-22",
  133. // avaUrl:
  134. // "https://pic4.zhimg.com/v2-a12b2d609fa2d5d16c10ea069419f3c3_xs.jpg"
  135. // },
  136. ],
  137. chooseId:0,
  138. titename:"",
  139. title: "",
  140. conv_id:"",
  141. duifangimg:"",
  142. };
  143. },
  144. props:['fuid','pcimg'],
  145. mounted() {
  146. this.uid = this.fuid;//可以自己写个假数据
  147. setTimeout(() => {
  148. this.getChatList();
  149. }, 300);
  150. //this.initWebsocket();
  151. },
  152. watch:{ //监听value的变化,进行相应的操做便可
  153. fuid: function(a,b){ //a是value的新值,b是旧值
  154. this.uid = this.fuid;
  155. this.chatList =[]
  156. this.getChatList();
  157. }
  158. },
  159. methods: {
  160. //发送信息
  161. sendmsg(event) {
  162. event.preventDefault()
  163. let msg = {"type":"send","send_id":this.uid,"receive_id":this.chooseId,"msg_type":"1","content":this.msg};
  164. if (this.$webSocket.ws && this.$webSocket.ws.readyState == 1) {
  165. this.$webSocket.ws.send(JSON.stringify(msg));
  166. }
  167. setTimeout(() => {
  168. this.getMsgList(this.conv_id);
  169. }, 500)
  170. this.msg = "";
  171. },
  172. //滚动条滚动到底部
  173. scrollBottm() {
  174. let el = this.$refs["MessageBox"];
  175. el.scrollTop = el.scrollHeight;
  176. },
  177. //选择联系人
  178. chooseUser(user){
  179. this.chooseId = user.uid;
  180. this.titename = user.nickname;
  181. this.getMsgList(user.conv_id);
  182. },
  183. //获取聊天列表
  184. getChatList(){
  185. axios.post("聊天列表接口",{uid:this.uid}).then(res=>{
  186. if(res.data.success == true){
  187. this.userList = res.data.data;
  188. if(this.userList.length>0){
  189. this.chooseId = this.userList[0].uid;
  190. this.titename = this.userList[0].nickname;
  191. this.conv_id = this.userList[0].conv_id;
  192. this.getMsgList(this.userList[0].conv_id);
  193. this.duifangimg = this.userList[0].avatar;
  194. }else{
  195. this.chooseId = '';
  196. this.titename = '';
  197. }
  198. }
  199. })
  200. },
  201. //获取聊天记录
  202. getMsgList(chooseId){
  203. axios.post("聊天记录接口",{cid:chooseId,uid:this.uid,pagesize:'10'}).then(res=>{
  204. if(res.data.success == true){
  205. this.chatList = res.data.data;
  206. let msgNums = 0;
  207. for(let i=0;i<this.userList.length;i++){
  208. if(this.userList[i].conv_id == chooseId){
  209. msgNums = this.userList[i].unreadCount;
  210. this.userList[i].unreadCount = 0;
  211. this.$emit('getInitData',this.fuid,msgNums);
  212. }
  213. }
  214. setTimeout(() => {
  215. this.scrollBottm();
  216. }, 50);
  217. }
  218. })
  219. },
  220. //隐藏字符串
  221. customMethod(type,msg){
  222. if(type == '1'){
  223. if(msg.length<10){
  224. return msg;
  225. }else{
  226. this.title=msg.substring(0,10)+'...';
  227. return msg.substring(0,10)+'...';
  228. }
  229. }else {
  230. this.title='媒体消息';
  231. return '[媒体消息]';
  232. }
  233. },
  234. //重新计算未读消息数
  235. getUnreadNum(msgNums){
  236. //把未读消息数清空
  237. // for (let index = 0; index < this.$store.state.permission.customerList.length; index++) {
  238. // if(this.fuid == this.$store.state.permission.customerList[index].id){
  239. // if(this.$store.state.permission.customerList[index].msgNum != null && this.$store.state.permission.customerList[index].msgNum >= msgNums){
  240. // this.$store.state.permission.customerList[index].msgNum = this.$store.state.permission.customerList[index].msgNum - msgNums;
  241. // }else{
  242. // this.$store.state.permission.customerList[index].msgNum = 0;
  243. // }
  244. // }
  245. // }
  246. // for (let index = 0; index < this.$store.state.permission.expertList.length; index++) {
  247. // if(this.fuid == this.$store.state.permission.expertList[index].id){
  248. // if(this.$store.state.permission.expertList[index].msgNum != null && this.$store.state.permission.expertList[index].msgNum >= msgNums){
  249. // this.$store.state.permission.expertList[index].msgNum = this.$store.state.permission.expertList[index].msgNum - msgNums;
  250. // }else{
  251. // this.$store.state.permission.expertList[index].msgNum = 0;
  252. // }
  253. // }
  254. // }
  255. }
  256. }
  257. }
  258. </script>
  259. <style lang="scss" scoped>
  260. .Contact {
  261. height: 704px;
  262. width: 100%;
  263. background-color: #fff;
  264. border: 1px solid #ebebeb;
  265. box-shadow: 0 0 4px 0 rgba(26, 26, 26, 0.1);
  266. border-radius: 3px;
  267. display: flex;
  268. //联系人
  269. .ContactSide {
  270. width: 500px;
  271. height: 100%;
  272. border-right: 1px solid #ebebeb;
  273. .ContactSide-tip {
  274. height: 60px;
  275. line-height: 40px;
  276. font-weight: 600;
  277. padding: 0 30px;
  278. border-bottom: 1px solid #ebebeb;
  279. }
  280. }
  281. .ContactItem {
  282. padding: 12px 20px 12px 29px;
  283. cursor: pointer;
  284. display: flex;
  285. border-bottom: 1px solid #f7f8fa;
  286. .UserContent {
  287. flex: 1;
  288. .UserMsg {
  289. display: flex;
  290. align-items: center;
  291. justify-content: space-between;
  292. .UserName {
  293. font-size: 15px;
  294. columns: #444444;
  295. font-weight: 600;
  296. }
  297. .MsgTime {
  298. font-size: 12px;
  299. color: #999999;
  300. float: right;
  301. }
  302. }
  303. }
  304. }
  305. .ChooseItem{
  306. background: #f5f4f4;
  307. }
  308. .UserAvator {
  309. width: 40px;
  310. height: 40px;
  311. border-radius: 50%;
  312. margin-right: 10px;
  313. }
  314. .ContactBox {
  315. width: 100%;
  316. &-header {
  317. background: #fafafa;
  318. font-size: 15px;
  319. // margin: 0 14px;
  320. // height: 20px;
  321. padding-bottom: 21px;
  322. padding-top: 22px;
  323. border-bottom: 1px solid #ebebeb;
  324. font-weight: 600;
  325. text-align: center;
  326. }
  327. //聊天框
  328. .MessageBox {
  329. height: 470px;
  330. overflow: scroll;
  331. .Message {
  332. display: flex;
  333. margin: 20px;
  334. .UserMsg {
  335. max-width: 388px;
  336. border-radius: 8px;
  337. padding: 6px 12px;
  338. font-size: 14px;
  339. position: relative;
  340. margin: 0 8px;
  341. text-align: left;
  342. white-space: pre-wrap;
  343. word-break: break-all;
  344. }
  345. .LeftMessage {
  346. background-color: #f6f6f6;
  347. color: #444;
  348. &::after {
  349. content: "";
  350. position: absolute;
  351. width: 8px;
  352. height: 8px;
  353. left: -4px;
  354. top: 14px;
  355. background: #f6f6f6;
  356. -webkit-transform: rotate(45deg);
  357. transform: rotate(45deg);
  358. }
  359. }
  360. .RightMessage {
  361. background-color: #0084ff;
  362. color: #fff;
  363. &::after {
  364. content: "";
  365. position: absolute;
  366. width: 8px;
  367. height: 8px;
  368. right: -4px;
  369. top: 14px;
  370. background: #0084ff;
  371. -webkit-transform: rotate(45deg);
  372. transform: rotate(45deg);
  373. }
  374. }
  375. }
  376. }
  377. //输入框
  378. .InputBox {
  379. padding: 0 10px;
  380. border-top: 1px solid #ebebeb;
  381. display: flex;
  382. flex-direction: column;
  383. justify-content: space-between;
  384. height: 168px;
  385. background: #fff;
  386. z-index: 10;
  387. .InputTextarea {
  388. margin-top: 20px;
  389. width: 100%;
  390. border: none;
  391. font-size: 14px;
  392. flex: 1;
  393. height:90px;
  394. }
  395. &-footer {
  396. display: flex;
  397. align-items: center;
  398. justify-content: flex-end;
  399. height: 40px;
  400. .FooterDesc {
  401. font-size: 14px;
  402. color: #bfbfbf;
  403. padding-right: 10px;
  404. }
  405. .sendButton {
  406. color: #fff;
  407. background-color: #0084ff;
  408. border-radius: 6px;
  409. width: 72px;
  410. height: 32px;
  411. font-size: 13px;
  412. line-height: 32px;
  413. text-align: center;
  414. }
  415. }
  416. }
  417. }
  418. }
  419. </style>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/892347
推荐阅读
相关标签
  

闽ICP备14008679号