zoukankan      html  css  js  c++  java
  • vue-cli使用sockjs即时通信

      基于webSocket通信的库主要有 socket.ioSockJS,这次用的是 SockJS。

      这里我们使用sockjs-clientstomjs这两个模块,要实现webSocket通信,需要后台配合,也使用相应的模块。

    1、sockjs-client

      sockjs-client是从SockJS中分离出来的用于客户端使用的通信模块,所以我们就直接来看看SockJS。SockJS是一个浏览器的JavaScript库,它提供了一个类似于网络的对象,SockJS提供了一个连贯的、跨浏览器的JavaScriptAPI,它在浏览器和Web服务器之间创建了一个低延迟、全双工、跨域通信通道。你可能会问,我为什么不直接用原生的WebSocket而要使用SockJS呢?这得益于SockJS的一大特性,一些浏览器中缺少对WebSocket的支持,因此回退选项是必要的,而Spring框架提供了基于SockJS协议的透明的回退选项。SockJS提供了浏览器兼容性,优先使用原生的WebSocket,如果某个浏览器不支持WebSocket,SockJS会自动降级为轮询。

    2、stomjs

      STOMP(Simple Text-Orientated Messaging Protocol) 面向消息的简单文本协议,WebSocket是一个消息架构,不强制使用任何特定的消息协议,它依赖于应用层解释消息的含义。与HTTP不同,WebSocket是处在TCP上非常薄的一层,会将字节流转化为文本/二进制消息,因此,对于实际应用来说,WebSocket的通信形式层级过低,因此可以在 WebSocket 之上使用STOMP协议,来为浏览器 和 server间的通信增加适当的消息语义。

      STOMP与WebSocket 的关系:

      HTTP协议解决了web浏览器发起请求以及web服务器响应请求的细节,假设HTTP协议不存在,只能使用TCP套接字来编写web应用,你可能认为这是一件疯狂的事情

      直接使用WebSocket(SockJS)就很类似于使用TCP套接字来编写web应用,因为没有高层协议,就需要我们定义应用间发送消息的语义,还需要确保连接的两端都能遵循这些语义;

      同HTTP在TCP套接字上添加请求-响应模型层一样,STOMP在WebSocket之上提供了一个基于帧的线路格式层,用来定义消息语义.

    3、代码实现:

      先安装 sockjs-client 和 stompjs

    npm install sockjs-client
    npm install stompjs

      简单代码:

    <script>
      import SockJS from 'sockjs-client'
      import Stomp from 'stompjs'
      import { getLiveUrlApi, getLiveEventDetailApi } from '@/apis'
      import { mapGetters } from 'vuex'
      import { picklist, isWinxin, isMobile, initWxShare } from '@/utils'
      import Emoji from './emoji'
      export default {
        data () {
          return {
            stompClient: '',
            timer: '',
            player: null,
            pkl: picklist,
            danmukuList: [],
            barrageInfo: {
              text: ''
            },
            total: 0,
            eventInfo: {
              endTime: '',
              speakers: [{}]
            },
            emojiShow: false,
            noticeShow: false,
            sharehref: '',
            isWeixinBrowser: isWinxin(),
            isMobileBrowser: isMobile()
          }
        },
        computed: {
          ...mapGetters(['token', 'userInfo', 'isSys', 'permissions']),
          isAdmin () {
            // sys、活动管理员、已报名且在直播的普通用户
            return this.isSys || (this.eventInfo.ticketStatus === 2 && this.eventInfo.liveStatus === 1) || this.permissions.includes('event')
          }
        },
        components: {
          Emoji
        },
        methods: {
          getEvent () {
            getLiveEventDetailApi(this.$route.params.id).then(res => {
              if (res.status === 200) {
                this.eventInfo = res.data
                if (this.isWeixinBrowser) {
                  this.initShare()
                }
                if (this.isAdmin) {
                  this.fetchData()
                }
              }
            })
          },
          fetchData () {
            getLiveUrlApi(this.$route.params.id).then(res => {
              if (res.status === 200) {
                this.aliPlay(res.data)
              }
            })
          },
          // 阿里云视频直播
          aliPlay (source) {
            let _videoDom = document.getElementById('aliVedio')
            let _ch = _videoDom.clientHeight / 2 - 32
            let _cw = _videoDom.clientWidth / 2 - 32
            this.player = new Aliplayer({
              id: 'aliVedio',
               '100%',
              source: source,
              autoplay: true,
              isLive: true,
              rePlay: false,
              playsinline: true,
              preload: true,
              controlBarVisibility: 'hover',
              useH5Prism: true,
              enableStashBufferForFlv: false,
              stashInitialSizeForFlv: 32,
              skinLayout: [
                {
                  'name': 'bigPlayButton',
                  'align': 'blabs',
                  'x': _cw,
                  'y': _ch
                },
                {
                  'name': 'controlBar',
                  'align': 'blabs',
                  'x': 0,
                  'y': 0,
                  'children': [
                    {
                      'name': 'liveDisplay',
                      'align': 'tlabs',
                      'x': 15,
                      'y': 6
                    },
                    {
                      'name': 'fullScreenButton',
                      'align': 'tr',
                      'x': 10,
                      'y': 14
                    },
                    {
                      'name': 'volume',
                      'align': 'tr',
                      'x': 5,
                      'y': 13
                    }
                  ]
                }
              ],
              components: [{
                name: 'AliplayerDanmuComponent',
                type: AliPlayerComponent.AliplayerDanmuComponent,
                args: [this.danmukuList]
              }]
            }, function (player) {
              player._switchLevel = 0
            })
          },
          // 连接后台
          connection () {
            let that = this
            // 建立连接对象
            let sockUrl = '/api/event-websocket?token=' + this.token.substring(7) + '&eventId=' + this.$route.params.id
            let socket = new SockJS(sockUrl)
            // 获取STOMP子协议的客户端对象
            this.stompClient = Stomp.over(socket)
            // 定义客户端的认证信息,按需求配置
            let headers = {
              Authorization: ''
            }
            // 向服务器发起websocket连接
            this.stompClient.connect(headers, (res) => {
              // 订阅服务端提供的某个topic
              this.stompClient.subscribe('/topic/event/' + this.$route.params.id, (frame) => {
                that.addBarage(JSON.parse(frame.body))
              })
              that.sentFirst()
            }, (err) => {
              console.log('失败:' + err)
            })
            this.stompClient.debug = null
          },
          // 断开连接
          disconnect () {
            if (this.stompClient) {
              this.stompClient.disconnect()
            }
          },
          // 初始化websocket
          initWebSocket () {
            this.connection()
            let that = this
            // 断开重连机制,尝试发送消息,捕获异常发生时重连
            this.timer = setInterval(() => {
              try {
                that.stompClient.send('connect-test')
              } catch (err) {
                console.log('断线了: ' + err)
                that.connection()
              }
            }, 5000)
          },
          // 用户加入发送弹幕
          keyDown (e) {
            if (e.keyCode === 13) {
              if (e.preventDefault) {
                e.preventDefault()
              } else {
                window.event.returnValue = false
              }
              this.sentBarrage()
            }
          },
          sentBarrage () {
            this.emojiShow = false
            if (this.barrageInfo.text === '' || this.barrageInfo.text === '
    ') {
              this.barrageInfo.text = ''
              return false
            }
            let that = this
            this.barrageInfo.eventId = this.eventInfo.id
            this.barrageInfo.name = this.userInfo.account
            this.barrageInfo.role = this.userInfo.roleName
            if (this.permissions.length > 0) {
              this.barrageInfo.role = 'admin'
            }
            this.barrageInfo.headimgurl = this.userInfo.headimgurl
            let reg = /#[u4E00-u9FA5]{1,4};/gi
            this.barrageInfo.comment = this.barrageInfo.text
            if (reg.test(this.barrageInfo.text)) {
              this.barrageInfo.text = this.barrageInfo.text.replace(reg, '')
            }
            this.stompClient.send(
              '/msg',
              {},
              JSON.stringify(that.barrageInfo)
            )
            this.barrageInfo.text = ''
          },
          // 连接建立,首次发送消息
          sentFirst () {
            let that = this
            this.barrageInfo.eventId = this.eventInfo.id
            this.barrageInfo.name = this.userInfo.account
            this.barrageInfo.role = this.userInfo.roleName
            if (this.permissions.length > 0) {
              this.barrageInfo.role = 'admin'
            }
            this.barrageInfo.headimgurl = this.userInfo.headimgurl
            this.stompClient.send(
              '/msg',
              {},
              JSON.stringify(that.barrageInfo)
            )
          },
          // 添加弹幕内容
          addBarage (content) {
            // 推送直播状态修改页面
            if (content.live) {
              if (this.isSys || this.permissions.includes('event')) {
                return
              }
              this.getEvent()
            }
            if (content.onlineCount) {
              this.total = content.onlineCount
            }
            let _obj = {
              'mode': 1,
              'stime': 1000
            }
            content = Object.assign(_obj, content)
            this.danmukuList.push(content)
            this.$nextTick(() => {
              let barrage = document.getElementById('barrage')
              barrage.scrollTop = barrage.scrollHeight
            })
          },
          // 将匹配结果替换表情图片
          emotion (res) {
            let word = res.replace(/#|;/gi, '')
            const list = [
              '微笑', '咧嘴笑', '破涕为笑', '', '眯眼', '', '害羞', '放电',
              '亲亲', '得意', '惊恐', '眼泪', '', '', '吐舌', '害羞笑',
              '', '同意', '拍手', '鼓掌', '红唇', '', '夜晚', '少儿不宜',
              '强壮', '', '太阳', '香蕉', '举杯', '国旗', '心动', '奶牛',
              '恶魔', '礼物', '鸡腿', '玫瑰', '西红柿', '茄子', '西瓜', '草莓'
            ]
            let index = list.indexOf(word)
            return `<img src="https://cdn.enmotech.com/attach/twemoji/${index}.png" align="middle" width="28px">`
          },
          setEmoji (arg) {
            this.barrageInfo.text += arg
          },
          // 微信分享
          initShare () {
            let _obj = {
              title: '活动直播:' + this.eventInfo.title,
              img: 'https://cs.enmotech.com/image/event/event_1556264441839.png',
              desc: '我正在观看' + this.eventInfo.speakers[0].name + '的直播:《' + this.eventInfo.title + '》,快来围观吧!'
            }
            initWxShare(_obj)
          }
        },
        mounted () {
          this.sharehref = location.href
          this.getEvent()
          this.initWebSocket()
        },
        beforeDestroy () {
          if (this.player) {
            this.player.dispose()
            this.player = null
          }
          // 页面离开时断开连接,清除定时器
          this.disconnect()
          clearInterval(this.timer)
        }
      }
    </script>
  • 相关阅读:
    CentOS7.6安装Kubernetes v1.15.1
    数据库三大范式
    linux
    linux
    linux
    linux
    Django contenttypes组件
    Django自带的用户认证
    Django rest framework(7) ---分页
    Django rest framework(6) ---序列化
  • 原文地址:https://www.cnblogs.com/goloving/p/10686826.html
Copyright © 2011-2022 走看看