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>
  • 相关阅读:
    CodeForces 785D Anton and School
    CodeForces 785C Anton and Fairy Tale
    CodeForces 785B Anton and Classes
    CodeForces 785A Anton and Polyhedrons
    爱奇艺全国高校算法大赛初赛C
    爱奇艺全国高校算法大赛初赛B
    爱奇艺全国高校算法大赛初赛A
    EOJ 3265 七巧板
    EOJ 3256 拼音魔法
    EOJ 3262 黑心啤酒厂
  • 原文地址:https://www.cnblogs.com/goloving/p/10686826.html
Copyright © 2011-2022 走看看