第一步:先创建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>