当前位置:   article > 正文

vue手把手带你创建聊天室(vue-native-websocket)

vue-native-websocket

vue手把手带你创建聊天室(vue-native-websocket)

谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口
[1] 。

正文开始:
socket中使用了VUEX如果不打算使用状态管理器,可以忽略下文中的某些配置。

在vue中我们使用:vue-native-websocket
第一步安装:

npm install vue-native-websocket --save
  • 1

然后在main.js中进行全局注册:

Vue.use(VueNativeSock,"后台地址*****",{
  // 启用Vuex集成
  store: store,
  // 数据发送/接收使用使用json
  format: "json",
  connectManually: true,
  reconnection: true,
 // 尝试重连的次数
 reconnectionAttempts: 5,
 // 重连间隔时间
 reconnectionDelay: 3000,
  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;
  }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

第三部写html:
在一个.vue结尾的文件中写入一下代码:

<!--公用组件:消息内容展示,实现群聊和单聊业务-->
<template>
    <div id="mainContent" >
        <div class="top-panel" ref="topPanel">
            <div class="title-panel">
                <!-- <p>当前在线人数: {{onlineUsers}}</p> -->
            </div>
        </div>
        <!--消息显示-->
        <div class="messages-panel" ref="messagesContainer">
            <div class="row-panel" v-for="(item,index) of senderMessageList" :key="index">
                <!--发送者消息样式-->
                <div class="sender-panel" v-if="item.userID == userID">
                    <!--昵称展示-->
                    <div class="user-name-panel sender">
                        <p>{{item.username}}</p>
                    </div>
                    <!--消息-->
                    <div class="msg-body">
                        <!--消息尾巴-->
                        <div class="tail-panel">
                            <svg class="icon" aria-hidden="true">
                                <use xlink:href="#icon-zbds30duihuakuangyou" color="#dce7dc"></use>
                            </svg>
                        </div>
                        <!--消息内容-->
                        <p v-html="item.msgText" @click="viewLargerImage($event)" ref="comment"/>
                    </div>
                    <!--头像-->
                    <div class="avatar-panel">
                        <img :src="item.avatarSrc" alt="">
                    </div>
                </div>
                <!--对方消息样式-->
                <div class="otherSide-panel" v-else>
                    <!--头像-->
                    <div class="avatar-panel">
                        <img :src="item.avatarSrc" alt="">
                    </div>
                    <!--昵称展示-->
                    <div class="user-name-panel sender">
                        <p>{{item.username}}</p>
                    </div>
                    <!--消息-->
                    <div class="msg-body">
                        <!--消息尾巴-->
                        <div class="tail-panel">
                            <svg class="icon" aria-hidden="true">
                                <use xlink:href="#icon-zbds30duihuakuangzuo"></use>
                            </svg>
                        </div>
                        <!--消息内容-->
                        <p v-html="item.msgText" @click="viewLargerImage($event)" ref="comment" />
                    </div>
                </div>
            </div>
        </div>
        <!--用户输入模块-->
        <div class="user-input-panel" @click="getEditableDivFocus()">
            <div class="toolbar-panel">
                <div class="item-panel" v-for="(item ,index) of toolbarList" :key="index">
                    <img class="emoticon" :src="require(`../assets/img/${item.src}`)"
                         @mouseenter="toolbarSwitch('hover',$event,item.src,item.hover,item.down,item.name)"
                         @mouseleave="toolbarSwitch('leave',$event,item.src,item.hover,item.down,item.name)"
                         @mousedown="toolbarSwitch('down',$event,item.src,item.hover,item.down,item.name)"
                         @mouseup="toolbarSwitch('up',$event,item.src,item.hover,item.down,item.name)" :alt="item.info">
                </div>
            </div>
            <div id="msgInputContainer" class="input-panel" ref="msgInputContainer" @keydown.enter.exact="sendMessage($event)"
                 contenteditable="true" spellcheck="false">
            </div>
             <div class="send-panel" ref="sendPanel" @click="mobileSend()">
                    <p>发送</p>
                </div>
            <!--表情面板-->
            <div class="emoticon-panel" :style="{display: emoticonShowStatus}" ref="emoticonPanel">
                <div class="row-panel">
                    <div class="item-panel" v-for="(item,index) of this.emojiList" :key="index">
                        <img :src="require(`../assets/images/emoji/${item.src}`)" :alt="item.info"
                             @mouseover="emojiConversion($event,'over',item.src,item.hover,item.info)"
                             @mouseleave="emojiConversion($event,'leave',item.src,item.hover,item.info)"
                             @click="emojiConversion($event,'click',item.src,item.hover,item.info)">
                    </div>
                </div>
                <div class="ico-panel"></div>
            </div>
        </div>
    </div>
</template>

<script src="../assets/js/message-display.js"></script>

<style lang="scss" src="../assets/css/message-display.scss" scoped></style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93

style文件:

#mainContent {
  width: 100%;
  height: 100%;

  .top-panel {
    width: 100%;
    height: 30px;
    display: flex;
    align-items: center;
    border-bottom: 1px solid #cecece;

    .title-panel {
      width: 70%;
      height: 25px;
      display: flex;
      align-items: center;

      .equipmentType {
        width: 18px;
        height: 18px;
        margin-left: 5px;

        img {
          width: 100%;
          height: 100%;
        }
      }
    }

    /*操作栏样式:单聊*/
    .operate-panel {
      width: 29%;
      height: 25px;

      .ico-panel {
        width: 100%;
        height: 100%;
        display: flex;
        justify-content: flex-end;
        align-items: center;

        .item-panel {
          width: 20px;
          height: 20px;

          img {
            width: 100%;
            height: 100%;
          }
        }
      }
    }

    /*操作栏样式:群聊*/
    // .operate-group-panel{

    // }
  }

  ::-webkit-scrollbar {
    width: 2px;
    /*滚动条宽度*/
    height: 6px;
    /*滚动条高度*/
  }

  .messages-panel {
    width: 100%;
    min-height: 400px !important;
    overflow-y: auto;
    max-height: 800px;
    overflow-x: hidden;
    padding-top: 5px;
    padding-bottom: 15px;

    .row-panel {
      width: 100%;
      min-height: 50px;

      /*对方消息样式*/
      .otherSide-panel {
        width: 96%;
        min-height: 50px;
        display: flex;
        margin-bottom: 15px;
        position: relative;

        .avatar-panel {
          width: 30px;
          min-width: 30px;
          height: 30px;
          border-radius: 50%;
          overflow: hidden;

          img {
            width: 100%;
            height: 100%;
          }
        }

        .user-name-panel {
          width: 240px;
          height: 20px;
          position: absolute;
          left: 42px;
          top: 2px;
          display: flex;
          justify-content: flex-start;

          align-items: center;

          p {
            color: #9da9c6;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
          }
        }

        .msg-body {
          max-width: 95%;
          min-height: 40px;
          background: #f4f3f3;
          border-radius: 5px;
          display: flex;
          align-items: center;
          padding: 10px;
          box-sizing: border-box;
          margin-top: 28px;
          margin-left: 16px;
          position: relative;

          /*消息尾巴*/
          .tail-panel {
            width: 20px;
            height: 100%;
            position: absolute;
            left: -10px;
            svg {
              margin-top: 8px;
              color: #f3f3f3;
            }
           
          }

          p {
            font-size: 12px;
            /*自动换行*/
            word-wrap: break-word;
            overflow: hidden;
            cursor: pointer;

            img {
              width: 100%;
              height: 100%;
            }
          }
        }
      }

      /*发送者消息样式*/
      .sender-panel {
        width: 96%;
        min-height: 50px;
        float: right;
        margin-right: 12px;
        display: flex;
        justify-content: flex-end;
        margin-bottom: 15px;
        position: relative;

        .avatar-panel {
          width: 30px;
          min-width: 30px;
          height: 30px;
          border-radius: 50%;
          overflow: hidden;

          img {
            width: 100%;
            height: 100%;
          }
        }

        .user-name-panel {
          width: 240px;
          height: 20px;
          position: absolute;
          right: 42px;
          top: 2px;
          overflow: hidden;
          text-overflow: ellipsis;
          display: flex;
          justify-content: flex-end;
          align-items: center;

          p {
            color: #9da9c6;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
          }
        }

        .msg-body {
          max-width: 95%;
          min-height: 40px;
          background: #d8e8dc;
          border-radius: 5px;
          display: flex;
          align-items: center;
          padding: 10px;
          box-sizing: border-box;
          margin-top: 28px;
          margin-right: 16px;
          position: relative;
          /*消息尾巴*/
          .tail-panel {
            width: 20px;
            height: 100%;
            position: absolute;
            right: -18px;
            svg {
              margin-top: 8px;
              color: #f3f3f3;
            }
          }

          p {
            font-size: 12px;
            line-height: 23px;
            // 强制换行
            word-break: break-all;
            display: flex;
            align-items: center;
            cursor: pointer;
            img {
              width: 100%;
              height: 100%;
              display: block;
            }
          }
        }
      }
    }
  }

  .send-panel {
    width: 70px;
    height: 30px;
    background-image: linear-gradient(-90deg, #29bdd9 0%, #276ace 100%);
    text-align: center;
    color: white;
    border-radius: 5px;
    line-height: 30px;
    cursor: pointer;
    float: right;
    margin-right: 5px;
  }
  .user-input-panel {
    width: 100%;
    height: 160px;
    position: relative;
    border-top: 1px solid #cecece;

    .toolbar-panel {
      width: 100%;
      height: 40px;
      display: flex;
      align-items: center;

      .item-panel {
        width: 24px;
        height: 24px;
        margin-right: 20px;
        display: flex;
        justify-content: center;
        align-items: center;

        img {
          width: 100%;
          height: 100%;
        }
      }

     
    }
   
    .input-panel {
      width: 100%;
      min-height: 30px;
      max-height: 120px;
      overflow-y: auto;
      outline: none;
      display: flex;
      align-items: center;
      flex-flow: row wrap;
      // 强制换行
      word-break: break-all;
    }

    /*表情面板*/
    .emoticon-panel {
      width: 290px;
      height: 250px;
      border-radius: 5px;
      background: white;
      border: solid 1px #dfe0e0;
      padding: 20px;
      box-sizing: border-box;
      position: absolute;
      top: -260px;
      // left: -194px;
      display: flex;
      justify-content: flex-start;
      z-index: 9999999;
     
      .row-panel {
        width: 100%;
        height: 30px;
        display: flex;
        align-items: center;
        flex-flow: row wrap;

        .item-panel {
          width: 25px;
          height: 25px;
          margin-right: 6px;
          margin-bottom: 7px;
          position: relative;
          // 取消12的倍数的元素的右外边距
          // &:nth-child(12n){
          //   margin-right: 0;
          // }

          img {
            width: 100%;
            height: 100%;

            &:hover {
              width: 26px;
              height: 26px;
            }
          }
        }
      }

      .ico-panel {
        width: 0;
        height: 0;
        border-right: 6px solid transparent;
        border-left: 6px solid transparent;
        border-top: 6px solid #dfe0e0;
        position: absolute;
        bottom: -6px;
        img {
          width: 100%;
          height: 100%;
        }
      }
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363

JS:

import emoji from '../json/emoji';
import toolbar from '../json/toolbar';
import lodash from 'lodash';
import base from "./base";
import VueCookies from "vue-cookies";



export default {
    name: "message-display",
    data() {
        return {
            danmu: null,
            id: '1',
            roomid: '',
            images: [],
            userID: '',
            worker:null,
            ws:null,
            isHide:true,
            messagesContainerTimer: "",
            onlineUsers: this.$store.state.onlineUsers,
            createDisSrc: require("../img/titlebar_function_createDis_normal@2x.png"),
            resourceObj: {
                createDisNormal: require("../img/titlebar_function_createDis_normal@2x.png"),
                createDisHover: require("../img/titlebar_function_createDis_hover@2x.png"),
                createDisClick: require("../img/titlebar_function_createDis_normal_p@2x.png"),
                phoneNormal: require("../img/phone_normal_ap@2x.png"),
                groupMsgImg: require("../img/group-msg-img.png"),
                avatarImg: require("../img/avatar.jpg"),
                msgImgTest: require("../img/msg-img-test.gif"),
                msgImgTestB: require("../img/msg-img-testB.gif"),
            },
            // 消息内容
            messageContent: "",
            InputContent: "",
            emoticonShowStatus: "none",
            emojiList: emoji,
            toolbarList: toolbar,
            senderMessageList: [],
            audioCtx: null,
            // 声音频率
            arrFrequency: [
                196.00, 220.00, 246.94, 261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25, 587.33, 659.25, 698.46, 783.99, 880.00, 987.77, 1046.50
            ],
            testWorker: null
        }
    },
    mounted: function () {
        let that = this
        let uid = this.$cookies.get('u_id')
        let course_id = this.$route.query.id
        let s_id = this.$cookies.get('s_id')
        let tokens = this.$cookies.get('PHPSESSID')
        this.$store.commit("changeCourse", {
            uid: uid,
            s_id: s_id,
            name: course_id
        });
        function work() {
            onmessage = ({ data: { jobId, message ,classID} }) => {
                postMessage({ jobId, result: message});
            };
        }
        const makeWorker = f => {
            let hide = that.isHide
            let pendingJobs = {};
            let worker = new Worker(
                URL.createObjectURL(new Blob([`(${f.toString()})()`])) //Blob = Binary Large Object的缩写,直译为二进制大对象
            );
            worker.onmessage = ({ data: { result, jobId,classID } }) => {
              
                let  ws = new WebSocket('wss://apps.beiqujy.com/count' +`?room_id=${result[0][0]}&uid=${result[0][1]}&type=3&from=2&class_id=${result[1]}`)
                ws.onopen = function () {
                    let login_data = '{"type":3,"from":2,"client_name":"' + '' + '","room_id":"' + result[0][0]+ '","class_id":"' + result[1] + '","uid":"' + result[0][1] + '"}';
                    console.log(login_data)
                    ws.send('首次发送消息'+login_data);
                };
                ws.onmessage = function (evt) {
                    var received_msg = evt.data;
                
                };
                ws.onclose = function () {
                    if(that.isHide){
                        reconnect('wss://apps.beiqujy.com/count' +`?room_id=${result[0][0]}&uid=${result[0][1]}&type=3&from=2&class_id=${result[1]}`)
                    }
                };
                function reconnect(url) {
                    var connects
                    clearTimeout(connects);
                    connects = setTimeout(function () {     //没连接上会一直重连,设置延迟避免请求过多
                        var ws = new WebSocket(url);
                        ws.onopen = function () {
                            let login_data = '{"type":3,"from":2,"client_name":"' + '' + '","room_id":"' + result[0][0]+ '","class_id":"' + result[1] + '","uid":"' + result[0][1] + '"}';
                            console.log('重连后发送的消息'+login_data)
                            ws.send(login_data);
                        };
                        ws.onmessage = function (evt) {
                            var received_msgs = evt.data;
                          
                        };
                        ws.onclose = function () {
                         
                            if(that.isHide){
                                reconnect('wss://apps.beiqujy.com/count' +`?room_id=${result[0][0]}&uid=${result[0][1]}&type=3&from=2&class_id=${result[1]}`)
                            }
                        };
                    }, 5000);
                }
                // 调用resolve,改变Promise状态
                pendingJobs[jobId](result);
                // 删掉,防止key冲突
                delete pendingJobs[jobId];
            };
            return (...message) =>
                new Promise(resolve => {
                    const jobId = String(Math.random());
                    pendingJobs[jobId] = resolve;
                    worker.postMessage({ jobId, message });
                });
        };
        this.testWorker = makeWorker(work);    
        this.$nextTick(() => {
            this.testWorker([VueCookies.get("roomid"), this.$store.state.uid],this.$route.query.id).then(message => {
            });
        });
        //链接socket
        this.$connect(process.env.VUE_APP_SOCKET + `?course_id=${course_id}&uid=${uid}&type='students'&from=2&listen_id=123`);
        this.userID = this.$store.state.uid
        var i = 0
        // webAudioAPI兼容性处理
        window.AudioContext = window.AudioContext || window.webkitAudioContext;
        // 设置列容器高度
        this.$refs.messagesContainer.style.height = this.getThisWindowHeight() - 350 + "px";
        // 全局点击事件,点击表情框以外的地方,隐藏当前表情框
        document.addEventListener('click', (e) => {
            let thisClassName = e.target.className;
            if (thisClassName !== "emoticon-panel" && thisClassName !== "emoticon") {
                this.emoticonShowStatus = "none";
            }
        });
        //从本地存储中获取数据渲染页面
        this.renderPage("", "", 1);
        // 监听消息接收
        this.$options.sockets.onmessage = (res) => {
            const data = JSON.parse(res.data);
            console.log(data)
            // this.messageChange()
            this.$store.commit("changeMessage", {
                msg: data.data.message
            });
            if (data.code == 201 || data.code == 202  ) {
                return
            } else {
                // this.$store.state.onlineUsers = data.onlineUsers;
                // 更新在线人数
                // this.onlineUsers = data.onlineUsers;
                // 获取服务端推送的消息
                const msgObj = {
                    msg: data.data.msg,
                    avatarSrc: data.data.user_img,
                    userID: data.data.uid,
                    username: data.data.user_nicename
                };
                if (lodash.isEmpty(localStorage.getItem("msgArray"))) {
                    this.renderPage(JSON.parse(localStorage.getItem("msgArray")), msgObj, 0);
                } else {
                    this.renderPage(JSON.parse(localStorage.getItem("msgArray")), msgObj, 0);
                }
            }
        };
    },
    beforeDestroy() {
        // 页面销毁时,断开连接
        localStorage.setItem("msgArray", '[]')
        this.isHide = false
        this.closeWorker()
        this.$disconnect();
    },
    methods: {
        closeWorker() {
            // console.log(this.testWorker)
            // this.worker.terminate()
            this.testWorker=null
        },
        createDisEventFun: function (status) {
            if (status === "hover") {
                this.createDisSrc = this.resourceObj.createDisHover
            } else if (status === "leave") {
                this.createDisSrc = this.resourceObj.createDisNormal
            } else {
                this.createDisSrc = this.resourceObj.createDisClick
            }
        },
        getThisWindowHeight: () => window.innerHeight,
        getThisWindowWidth: () => window.innerWidth,
        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;
                        }
                    }
                }
                // 消息发送: 发送文字,为空则不发送
                if (msgText.trim().length > 0) {
                    var obj = {
                        uid: parseInt( this.$cookies.get('u_id')),
                        message: msgText,
                        type:'students',
                        from:2,
                        event:1,
                        listen_id:123,
                        course_id: parseInt( this.$route.query.id)
                        
                    }
                    this.$socket.sendObj(obj)
                    event.target.innerHTML = "";
                }
            }
        },
        mobileSend: function () {
            // 模拟触发回车事件
            this.fireKeyEvent(this.$refs.msgInputContainer, 'keydown', 13);
        },
        //  渲染页面
        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 < msgArray.length; i++) {
                        const thisSenderMessageObj = {
                            "msgText": msgArray[i].msg,
                            "msgId": i,
                            "avatarSrc": msgArray[i].avatarSrc,
                            "userID": msgArray[i].userID,
                            "username": msgArray[i].username
                        };
                        // 更新消息内容
                        this.messageContent = msgArray[i].msg;
                        // 向父组件传值
                        this.$emit('updateLastMessage', this.messageContent);
                        // 解析并渲染
                        this.messageParsing(thisSenderMessageObj);
                    }
                }
            } else {
                // 判断本地存储中是否有数据
                if (localStorage.getItem("msgArray") === null) {
                    // 新增记录
                    msgArray.push(msgObj);
                    // 更新消息内容
                    this.messageContent = msgObj.msg;
                    // 向父组件传值
                    this.$emit('updateLastMessage', this.messageContent);
                    localStorage.setItem("msgArray", JSON.stringify(msgArray));
                    for (let i = 0; i < msgArray.length; i++) {
                        const thisSenderMessageObj = {
                            "msgText": msgArray[i].msg,
                            "msgId": i,
                            "avatarSrc": msgArray[i].avatarSrc,
                            "userID": msgArray[i].userID,
                            "username": msgArray[i].username
                        };
                        // 解析并渲染
                        this.messageParsing(thisSenderMessageObj);
                    }
                } else {
                    // 更新记录
                    msgArray = JSON.parse(localStorage.getItem("msgArray"));
                    msgArray.push(msgObj);
                    localStorage.setItem("msgArray", JSON.stringify(msgArray));
                    // 更新消息内容
                    this.messageContent = msgObj.msg;
                    // 向父组件传值
                    this.$emit('updateLastMessage', this.messageContent);
                    const thisSenderMessageObj = {
                        "msgText": msgObj.msg,
                        "msgId": Date.now(),
                        "avatarSrc": msgObj.avatarSrc,
                        "userID": msgObj.userID,
                        "username": msgObj.username
                    };
                    // 解析并渲染
                    this.messageParsing(thisSenderMessageObj);
                }
            }
        },
        // 模拟触发事件
        fireKeyEvent: function (el, evtType, keyCode) {
            let doc = el.ownerDocument,
                win = doc.defaultView || doc.parentWindow,
                evtObj;
            if (doc.createEvent) {
                if (win.KeyEvent) {
                    evtObj = doc.createEvent('KeyEvents');
                    evtObj.initKeyEvent(evtType, true, true, win, false, false, false, false, keyCode, 0);
                } else {
                    evtObj = doc.createEvent('UIEvents');
                    Object.defineProperty(evtObj, 'keyCode', {
                        get: function () {
                            return this.keyCodeVal;
                        }
                    });
                    Object.defineProperty(evtObj, 'which', {
                        get: function () {
                            return this.keyCodeVal;
                        }
                    });
                    evtObj.initUIEvent(evtType, true, true, win, 1);
                    evtObj.keyCodeVal = keyCode;
                    if (evtObj.keyCode !== keyCode) {
                        console.log("keyCode " + evtObj.keyCode + " 和 (" + evtObj.which + ") 不匹配");
                    }
                }
                el.dispatchEvent(evtObj);
            } else if (doc.createEventObject) {
                evtObj = doc.createEventObject();
                evtObj.keyCode = keyCode;
                el.fireEvent('on' + evtType, evtObj);
            }
        },
        // 消息解析
        messageParsing: function (msgObj) {
            console.log(msgObj)
            // 解析接口返回的数据进行渲染
            let separateReg = /(\/[^/]+\/)/g;
            let msgText = msgObj.msgText;
            let finalMsgText = "";
            if(msgText && msgText != undefined){
                // 将符合条件的字符串放到数组里
                const resultArray = msgText.match(separateReg);
           
            if (resultArray !== null) {
                for (let item of resultArray) {
                    // 删除字符串中的/符号
                    item = item.replace(/\//g, "");
                    // 判断是否为图片: 后缀为.jpeg
                    if (this.isImg(item)) {
                        const imgSrc = `${base.lkBaseURL}/uploads/chatImg/${item}`;
                        // 获取图片宽高
                        let imgInfo = {
                            "imgWidth": this.getQueryVariable(imgSrc, "width"),
                            "imgHeight": this.getQueryVariable(imgSrc, "height")
                        };
                        let thisImgWidth = 0;
                        let thisImgHeight = 0;
                        if (imgInfo.imgWidth < 400) {
                            thisImgWidth = imgInfo.imgWidth;
                            thisImgHeight = imgInfo.imgHeight;
                        } else {
                            // 缩放四倍
                            thisImgWidth = imgInfo.imgWidth / 4;
                            thisImgHeight = imgInfo.imgHeight / 4;
                        }
                        // 找到item中?位置,在?之前添加\\进行转义,解决正则无法匹配特殊字符问题
                        const charIndex = item.indexOf("?");
                        // 生成正则表达式条件,添加\\用于对?的转义
                        const regularItem = this.insertStr(item, charIndex, "\\");
                        // 解析为img标签
                        const imgTag = `<img width="${thisImgWidth}" height="${thisImgHeight}" src="${imgSrc}" alt="聊天图片">`;
                        // 替换匹配的字符串为img标签:全局替换
                        msgText = msgText.replace(new RegExp(`/${regularItem}/`, 'g'), imgTag);
                    }
                    // 表情渲染: 遍历表情配置文件
                    for (let emojiItem of this.emojiList) {
                        // 判断捕获到的字符串与配置文件中的字符串是否相同
                        if (emojiItem.info === item) {
                            const imgSrc = require(`../img/emoji/${emojiItem.hover}`);
                            const imgTag = `<img src="${imgSrc}" width="28" height="28" alt="${item}">`;
                            // 替换匹配的字符串为img标签:全局替换
                            msgText = msgText.replace(new RegExp(`/${item}/`, 'g'), imgTag);
                        }
                    }
                }
                finalMsgText = msgText;
            } else {
                finalMsgText = msgText;
            }
        }
            msgObj.msgText = finalMsgText;
            // 渲染页面
            this.senderMessageList.push(msgObj);
            let hash = {}
            this.senderMessageList = this.senderMessageList.reduce((prev, array) => {
                if (array.username == undefined) {
                    hash[array.username] ? '' : hash[array.username] = true && prev.push(array)
                } else {
                    prev.push(array)
                }
                return prev
            }, [])
            // 修改滚动条位置
            this.$nextTick(function () {
                this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight;
            });
        },
        // 显示表情
        toolbarSwitch: function (status, event, path, hoverPath, downPath, toolItemName) {
            if (status === "hover" || status === "up") {
                event.target.src = require(`../img/${hoverPath}`);
            } else if (status === "leave") {
                event.target.src = require(`../img/${path}`);
            } else {
                // 可编辑div获取焦点
                this.getEditableDivFocus();
                event.target.src = require(`../img/${downPath}`);
                // 表情框显示条件
                if (toolItemName === "emoticon") {
                    if (this.emoticonShowStatus === "flex") {
                        this.emoticonShowStatus = "none";
                    } else {
                        this.emoticonShowStatus = "flex";
                    }
                } else {
                    this.emoticonShowStatus = "none";
                }
            }
        },
        // 判断一个对象是否为函数类型
        isFunction: function (obj) {
            return typeof obj === "function" && typeof obj.nodeType !== "number";
        },
        // 表情框鼠标悬浮显示动态表情
        emojiConversion: function (event, status, path, hoverPath, info) {
            if (status === "over") {
                event.target.src = require(`../img/emoji/${hoverPath}`);
            } else if (status === "click") {
                // 表情输入
                const imgSrc = require(`../img/emoji/${hoverPath}`);
                const imgTag = `<img src="${imgSrc}" width="28" height="28" alt="${info}">`;
                document.execCommand("insertHTML", false, imgTag);
            } else {
                event.target.src = require(`../img/emoji/${path}`);
            }
        },
        // base64转file
        convertBase64UrlToImgFile: function (urlData, fileName, fileType) {
            // 转换为byte
            let bytes = window.atob(urlData);
            // 处理异常,将ascii码小于0的转换为大于0
            let ab = new ArrayBuffer(bytes.length);
            let ia = new Int8Array(ab);
            for (let i = 0; i < bytes.length; i++) {
                ia[i] = bytes.charCodeAt(i);
            }
            // 转换成文件,添加文件的type,name,lastModifiedDate属性
            let blob = new Blob([ab], { type: fileType });
            blob.lastModifiedDate = new Date();
            blob.name = fileName;
            return blob;
        },
        // 判断是否为图片
        isImg: function (str) {
            return str.indexOf(".jpeg") !== -1;
        },
        viewLargerImage: function (event) {
            const imgSrc = event.target.src;
            if (typeof imgSrc !== "undefined") {
                // 清空图片数组
                this.images = [];
                this.images.push(imgSrc);
                this.show();
            }
        },
        // 获取url参数
        getQueryVariable: function (url, variable) {
            // 对url进行截取
            url = url.substring(url.indexOf("?"), url.length);
            var query = url.substring(1);
            var vars = query.split("&");
            for (var i = 0; i < vars.length; i++) {
                var pair = vars[i].split("=");
                if (pair[0] == variable) { return pair[1]; }
            }
            return false;
        },
        // 字符串指定位置添加字符
        insertStr: function (source, start, newStr) {
            return source.slice(0, start) + newStr + source.slice(start);
        },
        // 可编辑div获取焦点
        getEditableDivFocus: function () {
            // 开头获取焦点
            this.$refs.msgInputContainer.focus();
        },
        // 图片查看插件
        show() {
            const viewer = this.$el.querySelector('.images').$viewer
            viewer.show()
        }
    },
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505

至于表情包和一些聊天小组件,有需要的童鞋可以留言。

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号