给女朋友写的websoket

246 阅读1分钟

第一步:先创建socket文件

// import Vue from 'vue'
let socket = null
let lockReconnet = false // 避免重复连接
const wsUrl = 'ws://localhost:8001'
let isReconnet = false
let globalCallback = null
let sendData = null // 把要发送给socket的数据和处理socket返回数据的回调保存起来
let createSocket = (url) => {
  // 创建socket
  try {
    if ('WebSocket' in window) {
      socket = new WebSocket(url)
    } else if ('MozWebSocket' in window) {
      // eslint-disable-next-line no-undef
      socket = new MozWebSocket(url)
    }
    // Vue.prototype.socket = socket //需要主动关闭的话就可以直接调用this.socket.close()进行关闭,不需要的话这个可以去掉
    initSocket()
  } catch (e) {
    reconnet(url)
  }
}
let sendMsg = (data, callback) => {
  // 发送数据,接收数据
  if (socket.readyState === 1) {
    globalCallback = callback
    sendData = data

    data = JSON.stringify(data)
    socket.send(data)
  } else {
    setTimeout(() => {
      console.log(socket, '等待socket链接成功')
      sendMsg(data, callback)
    }, 1500)
    return false
  }
  socket.onmessage = (ev) => {
    callback && callback(ev)
  }
}
let initSocket = () => {
  // 初始化websocket
  socket.onopen = () => {
    console.log('socket连接成功')
    // heartCheck.reset().start() // 后端说暂时不需要做心跳检测

    if (isReconnet) {
      // 执行全局回调函数
      // console.log('websocket重新连接了')
      sendMsg(sendData, globalCallback)
      isReconnet = false
    }
  }

  socket.onmessage = (ev) => {
    console.log(ev, '连接正常11111111111111')
    heartCheck.reset().start() // 后端说暂时不需要做心跳检测
  }

  socket.onerror = () => {
    console.log('websocket服务出错了---onerror')
    reconnet(wsUrl)
  }

  socket.onclose = () => {
    console.log('websocket服务关闭了+++onclose')
    reconnet(wsUrl)
  }
}
let reconnet = (url) => {
  // 重新连接websock函数
  if (lockReconnet) return false

  isReconnet = true
  lockReconnet = true
  setTimeout(() => {
    createSocket(url)
    lockReconnet = false
  }, 2000)
}
let heartCheck = {
  // 心跳检测
  timeout: 60 * 1000,
  timeoutObj: null,
  serverTimeoutObj: null,
  reset() {
    clearTimeout(this.timeoutObj)
    clearTimeout(this.serverTimeoutObj)
    return this
  },
  start() {
    let that = this
    this.timeoutObj = setTimeout(() => {
      // 发送数据,如果onmessage能接收到数据,表示连接正常,然后在onmessage里面执行reset方法清除定时器
      socket.send('heart check')
      this.serverTimeoutObj = setTimeout(() => {
        socket.close()
      }, that.timeout)
    }, this.timeout)
  }
}
createSocket(wsUrl)
export default { sendMsg }

第二步:在main.js中引入,注册

import webSocket from './utils/webSocket'

Vue.config.productionTip = false
Vue.use(iView)
Vue.use(ElementUI)
Vue.prototype.sendMsg = webSocket.sendMsg

第三步:在页面使用--直接看send方法

this.sendMsg()第一个参数是要发送的内容,第二个参数是回调


<template>
  <div class="main-box">
    <div class="content">
      <div v-for="(item, index) in msgList" :key="index">
        <div :class="item.class">
          <div>
            <!-- {{ item.name }} -->
            <img :src="item.img" />
            <span>
              {{ item.time }}
            </span>
          </div>
          <div>
            {{ item.data }}
          </div>
        </div>
      </div>
    </div>
    <div class="send">
      <input v-model="msg" />
      <button @click="send" @keydown="keydown">send</button>
      <button @click="clear">clear</button>
    </div>
  </div>
</template>

<script>
import img1 from '../../static/img/img7.jpg'
import img2 from '../../static/img/img8.jpg'
export default {
  data() {
    return {
      msg: '',
      msgList: []
    }
  },
  methods: {
    hasScrollbar() {
      return (
        document.querySelector('.content').scrollHeight >
        (document.querySelector('.content').innerHeight ||
          document.querySelector('.content').clientHeight)
      )
    },
    keydown({ keyCode }) {
      console.log(keyCode, '2')
      if(keyCode===13) this.send()
    },
    clear() {
      this.msgList = []
    },
    send() {
      this.sendMsg(this.msg, (ev) => {
        console.log(ev.data)
        this.msgList.push({
          name: '我',
          data: this.msg,
          class: 'wo',
          img: img1,
          time:
            new Date().toLocaleDateString() +
            '  ' +
            new Date().toLocaleTimeString()
        })
        this.msg = ''
        setTimeout(() => {
          this.msgList.push({
            name: '后端',
            data: ev.data,
            img: img2,
            class: 'houduan',
            time:
              new Date().toLocaleDateString() +
              '  ' +
              new Date().toLocaleTimeString()
          })
          this.$nextTick(() => {
            if (this.hasScrollbar()) {
              document.querySelector('.content').scrollTop =
                document.querySelector('.content').scrollHeight
            }
          })
        }, 1000)
      })
    }
  }
}
</script>

<style scoped>
.content .wo {
  color: red;
}
.content img {
  width: 50px;
}
.wo > div:nth-child(1) {
  display: flex;
  align-items: center;
  flex-direction: row-reverse;
}
.wo > div:nth-child(2) {
  display: flex;
  flex-direction: row-reverse;
}
.content .wo div > span,
.content .houduan div > span {
  font-size: 12px;
  margin: 0 20px;
}
.content .houduan {
  color: blue;
}
.main-box {
  position: relative;
  height: 300px;
  border: 1px solid red;
  width: 300px;
  margin: auto;
  margin-top: 30px;
}
.send {
  position: absolute;
  bottom: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
}
.content {
  max-height: 256px;
  overflow: auto;
  padding: 20px;
}
</style>

最后把效果图奉上

1.png