精华内容
下载资源
问答
  • Vuejs 使用 vue-native-websocket

    千次阅读 2020-09-25 15:32:38
    yarn add vue-native-websocket # or npm install vue-native-websocket --save 使用 一、配置 通过URL字符串自动进行websocket连接 import VueNativeSock from 'vue-native-websocket' Vue.use(VueNativeSock, ...

    安装

    yarn add vue-native-websocket
    
    # or
    
    npm install vue-native-websocket --save
    
    

    使用

    一、配置

    通过URL字符串自动进行websocket连接

    import VueNativeSock from 'vue-native-websocket'
    Vue.use(VueNativeSock, 'ws://localhost:9090')
    

    二、连接实例

    1、自动连接

    启用ws自动重新连接(适用于整个系统多方面应用websocket接收消息):

    import Vue from 'vue'
    import VueNativeSock from 'vue-native-websocket'
    const socketUrl  = 'ws://' + window.location.host + '/hh-web/webSocket';
    
    Vue.use(VueNativeSock, socketUrl, {
        reconnection: true, // 自动重新连接 (false)
        reconnectionAttempts: Infinity, // 重新连接尝试次数 (Infinity),
        reconnectionDelay: 2000, // 重新连接时间间隔
      })
    

    2、手动连接

    启用ws手动连接(适用于系统单个页面接收处理websocket消息):

    import Vue from 'vue'
    import VueNativeSock from 'vue-native-websocket'
    const socketUrl  = 'ws://' + window.location.host + '/hh-web/webSocket';
    
    Vue.use(VueNativeSock, socketUrl, {
        connectManually: true,  //是否手动连接ws
        reconnectionAttempts: Infinity, // 重新连接尝试次数 (Infinity),
        reconnectionDelay: 2000, // 重新连接时间间隔
      })
    

    3、关于Vuejs实例的用法

    var vm = new Vue({
      methods: {
        clickButton: function(val) {
            // $socket is [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) instance
            this.$socket.send('some data')
            // or with {format: 'json'} enabled
            this.$socket.sendObj({awesome: 'data'})
        }
      }
    })
    

    4、创建和删除动态websocket事件监听器

    创建一个新的动态监听器

    this.$options.sockets.onmessage = (data) => console.log(data)
    

    删除现有监听器

    delete this.$options.sockets.onmessage
    
    

    三、应用实例

    自定义websocket事件处理
    1、事件名称
    2、函数定义
    3、原始/默认处理程序代码功能function (eventName, event)。这使您可以选择将事件移交给原始处理程序之前进行一些基本的预处理。
    这是执行一些预处理,然后将事件传递到原始处理程序代码的示例:

    实例

    1、新建websocket/index.js文件

    在这里插入图片描述

    2、在入口函数中引入websocket文件

    import { useSocket } from './modules/websocket'
    useSocket()
    
    

    3、编写websocket文件,自定义websocket事件处理

    3.1、引入websocket组件、定义常量
    import Vue from 'vue'
    import VueNativeSock from 'vue-native-websocket'
    
    const socketUrl  = 'ws://' + window.location.host + '/hh-web/webSocket';
    
    /* 定义并导出接收socket后触发的自定义在事件名 -- start */
    export const debugEvent = 'debugEvent'
    /* 定义并导出接收socket后触发的自定义在事件名 -- end */
    
    3.2、定义useSocket函数
    
    let socketBus
    
    function useSocket () {
      Vue.use(VueNativeSock, socketUrl, {
        reconnection: true, // 自动重新连接 (false)
        reconnectionAttempts: Infinity, // 重新连接尝试次数 (Infinity),
        reconnectionDelay: 2000, // 重新连接时间间隔
      })
      socketBus = new Vue()  //vue实例,用来绑定动态监听器 onclosed onmessage等事件
      socketBus.$options.sockets.onclose = () => {
        console.log('websocket closed')
      }
      socketBus.$options.sockets.onmessage = (e) => {
        let data
        try {
          data = JSON.parse(e.data)
        } catch (e) {
          console.log(e)
          data = null
        }
        handleSocketData(data)  //数据处理函数
      }
    }
    
    3.3、编写数据处理函数
    function handleSocketData (data) {
      if (!data) {
        return
      }
      switch (+data.eventType) {
        case 3:  // 设备调试返回结果
        socketBus.$emit(debugEvent, data)  //子组件向父组件传递debugEvent事件和data数据
          break;
      }
    }
    
    3.4、暴露定义的变量,以便父组件引用使用
    export { useSocket, socketUrl, socketBus }
    

    4、组件product.vue中使用websocket事件

    import { socketBus, debugEvent } from '@/modules/websocket'
    
     mounted () {
        socketBus.$on(debugEvent, this.dealResult)  //sockeBus绑定debugEvent事件
      },
      beforeDestroy () {
        socketBus.$off(debugEvent)     //sockeBus解绑debugEvent事件
      }
    
    
    展开全文
  • <div><p>This Pull Request updates devDependency <code>vue-native-websocket</code> (<a href="https://renovatebot.com/gh/nathantsoi/vue-native-websocket">source) from <code>v2.0.8</code> to <code>v2.0.9...
  • vue-native-websocket · native websocket implementation for Vuejs 2 and Vuex Install yarn add vue-native-websocket # or npm install vue-native-websocket --save Usage Configuration Automatic ...
  • vue手把手带你创建聊天室(vue-native-websocket) 谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据...

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

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

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

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

    npm install vue-native-websocket --save
    

    然后在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;
      }
    });
    

    第三部写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>
    

    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%;
            }
          }
        }
      }
    }
    

    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()
            }
        },
    }
    

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

    展开全文
  • 使用websocket很简单,不用去考虑模块化,组件之间的访问问题,面向文档编程即可,在Vue项目中使用时,远远没有想象中的那么简单,需要考虑很多场景,本篇文章将与各位开发者分享下 vue-native-websocket 库的使用...
  • Vue2、websocket 与node.js... 安装vue-native-websocket模块2. yarnaddvue-native-websocket或者用npminstallvue-native-websocket--save3. 在main.js中引入websocketimport websocket from 'vue-native-websocket'...

    Vue2、websocket 与node.js接口 本地测试

    1.  安装vue-native-websocket模块

    2.  yarn add vue-native-websocket

    或者用

    npm install vue-native-websocket --save

    3. 在main.js中引入websocket

    import websocket from 'vue-native-websocket'

    Vue.prototype.$websocket = websocket

    Vue.use(websocket, 'ws://localhost:3000', {

    reconnection: true, // (Boolean) whether to reconnect automatically (false)

    reconnectionAttempts: 5, // (Number) number of reconnection attempts before giving up (Infinity),

    reconnectionDelay: 3000, // (Number) how long to initially wait before attempting a new (1000)

    })

    项目中main.js使用如下图

    9dceb259cb635f56c93cfc06ffb9399f.png

    4.在项目中新建websocket.vue文件,在HelloWorld.vue中引入

    baeb2809167658b29afe4133453b816e.png

    5. HelloWorld.vue文件代码如下

    import websocket from "@/components/websocket"

    export default {

    name: 'HelloWorld',

    components:{

    websocket

    },

    data () {

    return {

    }

    },

    6.websocket.vue代码如下

    {{msg}}

    export default {

    name:"websocket",

    data() {

    return {

    websock: null,

    msg:""

    }

    },

    created(){

    //页面刚进入时开启长连接

    this.initWebSocket()

    },

    destroyed: function() {

    //页面销毁时关闭长连接

    this.websocketclose();

    },

    methods: {

    initWebSocket(){ //初始化weosocket

    const wsuri = 'ws://localhost:3000';//ws地址

    this.$websocket = new WebSocket(wsuri);

    this.$websocket.onopen = this.websocketonopen;

    this.$websocket.onerror = this.websocketonerror;

    this.$websocket.onmessage = this.websocketonmessage;

    this.$websocket.onclose = this.websocketclose;

    },

    websocketonopen() {

    console.log("WebSocket连接成功");

    },

    websocketonerror(e) { //错误

    console.log("WebSocket连接发生错误");

    },

    websocketonmessage(e){ //数据接收

    console.log(e);

    this.msg=e.data

    },

    websocketsend(agentData){//数据发送

    this.$websocket.send(agentData);

    },

    websocketclose(e){ //关闭

    console.log("connection closed (" + e.code + ")");

    },

    },

    }

    7.创建一个新的项目,新建1.js文件,用于写node.js接口,安装

    用cmd或者git bash进入后台接口文件,1.js,然后命令行输入node 1.js,启动后台服务。文件如下:

    var WebSocketServer = require('websocket').server;

    var http = require('http');

    var server = http.createServer(function(request, response) {

    console.log((new Date()) + ' Received request for ' + request.url);

    response.writeHead(404);

    response.end();

    });

    server.listen(3000, function() {

    console.log((new Date()) + ' Server is listening on port 3000');

    });

    wsServer = new WebSocketServer({

    httpServer: server,

    });

    wsServer.on('request', function(request) {

    //当前的连接

    var connection = request.accept(null, request.origin);

    setInterval(function(){

    connection.sendUTF('服务端发送消息' + (Math.random().toFixed(2)))

    },500)

    console.log((new Date()) + '已经建立连接');

    connection.on('message', function(message) {

    if (message.type === 'utf8') {

    console.log('Received Message: ' + message.utf8Data);

    connection.sendUTF(message.utf8Data);

    }

    else if (message.type === 'binary') {

    console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');

    connection.sendBytes(message.binaryData);

    }

    });

    connection.on('close', function(reasonCode, description) {

    console.log((new Date()) + ' Peer ' + connection.remoteAddress + '断开连接');

    });

    });

    8. Vue2、websocket 与node.js接口 本地测试到这里就结束了,以上代码用到Websocketd的方法详见websocket文档

    展开全文
  • Vue2、websocket 与node.js...1. 安装vue-native-websocket模块 2. yarnaddvue-native-websocket 或者用 npminstallvue-native-websocket--save 3. 在main.js中引入websocket import websocket from 'vue-...

    Vue2、websocket 与node.js接口 本地测试

    1.  安装vue-native-websocket模块
    2.  yarn add vue-native-websocket 
    或者用 
    npm install vue-native-websocket --save
     

    3. 在main.js中引入websocket

    import websocket from 'vue-native-websocket'

    Vue.prototype.$websocket = websocket

    Vue.use(websocket, 'ws://localhost:3000', {

      reconnection: true, // (Boolean) whether to reconnect automatically (false)

      reconnectionAttempts: 5, // (Number) number of reconnection attempts before giving up (Infinity),

      reconnectionDelay: 3000, // (Number) how long to initially wait before attempting a new (1000)

    })

     

     

    项目中main.js使用如下图

     

     

    4.在项目中新建websocket.vue文件,在HelloWorld.vue中引入

     

     

    5. HelloWorld.vue文件代码如下

     

    <template>

      <div class="hello">

       <websocket/>

      </div>

    </template>

     

    <script>

    import websocket from "@/components/websocket"

    export default {

      name: 'HelloWorld',

      components:{

        websocket

      },

      data () {

        return {

        

        }

      },

    </script>

     

    <!-- Add "scoped" attribute to limit CSS to this component only -->

    <style scoped>

     

    </style>

     

    6.websocket.vue代码如下

    <template>

        <div>

            {{msg}}

        </div>

    </template>

     

    <script>

        export default {

            name:"websocket",

            data() {

                return {

                    websock: null,

                    msg:""

                }

            },

     

        created(){

               //页面刚进入时开启长连接

                this.initWebSocket()

           },

        destroyed: function() {

        //页面销毁时关闭长连接

          this.websocketclose();

     

        },

     

        methods: {

     

          initWebSocket(){ //初始化weosocket

           

            const wsuri = 'ws://localhost:3000';//ws地址

     

            this.$websocket = new WebSocket(wsuri);

     

            this.$websocket.onopen = this.websocketonopen;

     

            this.$websocket.onerror = this.websocketonerror;

     

            this.$websocket.onmessage = this.websocketonmessage;

     

            this.$websocket.onclose = this.websocketclose;

           },

     

          websocketonopen() {

            console.log("WebSocket连接成功");

          },

     

          websocketonerror(e) { //错误

            console.log("WebSocket连接发生错误");

          },

     

          websocketonmessage(e){ //数据接收

            console.log(e);

    this.msg=e.data

          },

     

          websocketsend(agentData){//数据发送

            this.$websocket.send(agentData);

          },

     

          websocketclose(e){ //关闭

            console.log("connection closed (" + e.code + ")");

         },

       },

      }

     </script>

     

    7.创建一个新的项目,新建1.js文件,用于写node.js接口,安装

    nodejs-websocket模块npm install websocket

    用cmd或者git bash进入后台接口文件,1.js,然后命令行输入node 1.js,启动后台服务。文件如下:

    var WebSocketServer = require('websocket').server;

    var http = require('http');

     

    var server = http.createServer(function(request, response) {

        console.log((new Date()) + ' Received request for ' + request.url);

        response.writeHead(404);

        response.end();

    });

    server.listen(3000, function() {

        console.log((new Date()) + ' Server is listening on port 3000');

    });

     

    wsServer = new WebSocketServer({

        httpServer: server,

     

    });

     

     

    wsServer.on('request', function(request) {

        //当前的连接

        var connection = request.accept(null, request.origin);

     

        setInterval(function(){

            connection.sendUTF('服务端发送消息' + (Math.random().toFixed(2)))

        },500)

     

        console.log((new Date()) + '已经建立连接');

        connection.on('message', function(message) {

            if (message.type === 'utf8') {

                console.log('Received Message: ' + message.utf8Data);

                connection.sendUTF(message.utf8Data);

            }

            else if (message.type === 'binary') {

                console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');

                connection.sendBytes(message.binaryData);

            }

        });

        connection.on('close', function(reasonCode, description) {

            console.log((new Date()) + ' Peer ' + connection.remoteAddress + '断开连接');

        });

    });                                          

     

    8. Vue2、websocket 与node.js接口 本地测试到这里就结束了,以上代码用到Websocketd的方法详见websocket文档

     

    转载于:https://www.cnblogs.com/volodya/p/10195298.html

    展开全文
  • <div><p>When a page where a vue component is using the vue native websocket is loaded, it connects and works without any problem. After switching to another ...nathantsoi/vue-native-websocket</p></div>
  • 学习的动力源于兴趣,愿你在学习新知识时,动力源于...需要考虑很多场景,本篇文章将与各位开发者分享下vue-native-websocket库的使用以及配置,用其实现群聊功能。先看下最终实现的效果安装依赖本文中对于vue-nativ...
  • <div><p>链接如下:<a href="https://www.npmjs.com/package/vue-native-websocket-vue3">vue-native-websocket-vue3</a></p>该提问来源于开源项目:nathantsoi/vue-native-websocket</p></div>
  • 直接上链接:[https://github.com/leancloud/js-realtime-sdk/tree/master](https://github.com/leancloud/js-realtime-sdk/tree/master) ...https://github.com/nathantsoi/vue-native-websocket
  • Listener example

    2020-11-20 15:47:04
    I have vue-native-websocket and vuex already setup. I know i should use this code https://github.com/nathantsoi/vue-native-websocket#dynamic-socket-event-listeners but where?</p><p>该提问来源于开源...
  • Proxy is not defined - IE 11

    2020-12-04 16:30:49
    <div><p>Hello, <p>In Main.js file you use Proxy object and it's causes that my app not work in IE 11, because in IE 11 there is no Proxy object....nathantsoi/vue-native-websocket</p></div>

空空如也

空空如也

1 2 3 4
收藏数 75
精华内容 30
关键字:

vue-native-websocket

vue 订阅