uniapp中使用websocket实现实时聊天功能
直接贴代码
文档: https://uniapp.dcloud.io/api/request/websocket
//scroll-view组件的scroll-top属性:设置竖向滚动条位置。只要scroll-top大于滚动区域最大高度,即可滚动到底部
<scroll-view scroll-y="true" :scroll-top="commentScrollCount" class="comment-scroll-body">
。。。。。。
</scroll-view>
data(){
return{
commentList:[], //获取的评论列表
commentValue:'', //用户评论内容
isSocketOpen:false, //socket是否打开
pingpangTimes:null, //socket心跳计时器
}
}
onLoad(option) {
this.chatInit() //socket相关操作
},
beforeDestroy() {
clearInterval(this.pingpangTimes) //清除socket心跳定时器
uni.closeSocket() //关闭socket
},
methods:{
//链接socket以进行直播实时评论发送获取等相关操作
chatInit(){
uni.request({
url: `${this.$baseUrl}/api-live/checkLiveStatus?lid=${this.lid}&initial=1`, //此接口返回socket请求地址
method: 'GET',
success: res => {
if(res.data.code==200){
let socketlink=''
if(this.userToken){ //已登录,携带token
socketlink=`${res.data.msg}?token=${this.userToken}`
}else{ //未登录
socketlink=res.data.msg
}
this.commentList=[] //创建新的socket连接前先清除之前的实时聊天记录
uni.closeSocket() //创建新的socket连接前确保旧的已关闭
//创建一个socket连接
uni.connectSocket({
url:encodeURI(socketlink), //这里建议使用encodeURI编码,以解决ios上可能出现的连接兼容问题(猜测socketlink里存在中文、空格、特殊字符或link字符串过长时可能会在ios上出现连接问题)
})
//监听socket打开
uni.onSocketOpen(()=>{
this.isSocketOpen=true
console.log('WebSocket连接已打开!');
})
//监听socket关闭
uni.onSocketClose(()=>{
this.isSocketOpen=false
console.log('WebSocket连接已关闭!');
})
//监听socket错误
uni.onSocketError(()=>{
this.isSocketOpen=false
console.log('WebSocket连接打开失败');
})
//监听socket消息
uni.onSocketMessage((res)=>{
return this.getComment(res)
})
//先确保清除了之前的心跳定时器
clearInterval(this.pingpangTimes)
//每过一段时间发送一次心跳,发送Ping,服务器会反馈pong,防止断连
this.pingpangTimes=setInterval(()=>{
uni.sendSocketMessage({
data: "ping",
success:()=>{},
fail:()=>{
this.isSocketOpen=false
}
});
},60000)
}
},
});
},
//监听socket消息
getComment(res){
let infos=JSON.parse(res.data) //socket信息是字符串,需要先转成json形式再去解析内容
//后端规定cadmin为0--用户发言,为1--管理员发言,为2--系统提示,为3--需登录,为5--心跳信息
if(typeof(infos.cadmin)=="undefined"){ //infos.cadmin不存在说明返回的是数组,说明是第一次获取的之前的所有聊天记录
this.commentList=this.commentList.concat(infos)
//设置定时器,到时间后滚动到最底部。使用scroll-view组件的scroll-top属性。只要scroll-top的值大于滚动区域的最大高度即可实现滚动到最底部
let scrolltimes=setTimeout(()=>{
this.commentScrollCount=this.commentList.length*200
clearTimeout(scrolltimes)
},600)
//后续每次更新一条有效的新聊天(心跳信息pong不是有效聊天),就会触发这个
}else if(infos.cadmin==0||infos.cadmin==1||infos.cadmin==2){
this.commentList=this.commentList.concat(infos)
let scrolltimes=setTimeout(()=>{
this.commentScrollCount=this.commentList.length*200
clearTimeout(scrolltimes)
},150)
}else if(infos.cadmin==3){ //未登录
this.loginPopRemind="您尚未登录或您的登录已过期,请重新登录后发言"
uni.removeStorageSync('kusername')
uni.removeStorageSync('kuserid')
uni.removeStorageSync('kuserimg')
uni.removeStorageSync('kusertoken')
this.$refs.noLoginPopup.open()
}
}
//发表评论
sendComment(val){
if(val==""){
uni.showToast({title: '说点什么吧 ~',icon:'none'})
}else if(val.length>300){
uni.showToast({title: `评论字数请勿超过300个字符,当前 ${val.length}`,icon:'none'})
}else{
if(this.userToken){ //已登录
if(this.isSocketOpen){ //socket连接正常
this.commentValue=val
let theValue={
"ccontent":this.commentValue
}
let transedValue=JSON.stringify(theValue) //后端规定的评论数据格式:json转字符串
uni.sendSocketMessage({
data: transedValue,
success:()=>{
this.commentValue=""
uni.showToast({title: '发送成功',icon:'none'})
},
fail:()=>{
uni.showToast({title: '发送失败,请稍后再试或重新进入此页面尝试',icon:'none'})
}
});
}else{ //socket已断开
uni.showToast({title: '聊天断开啦,请重新进入此页面尝试 ~',icon:'none'})
}
}else{ //未登录
this.$refs.needLoginPopup.open()
}
}
},
}