web中使用websocket实现实时聊天功能

友情链接:uniapp中使用websocket实现实时聊天功能 https://www.cnblogs.com/huihuihero/p/13491922.html

直接贴代码

<div class="chat-content">
    <div class="comment-list" id="comment-list">
        <div class="every-comment" v-for="(item,index) in commentList" :key="index">
            <div class="every-comment-user" v-if="item.type==0">...</div>  <!-- 普通发言 -->
            <div class="every-comment-admin" v-if="item.type==1">...</div>  <!-- 管理员发言 -->
            <div class="every-comment-welcome" v-if="item.type==2">...</div>  <!-- 欢迎xx进入直播间 -->
            <div class="every-comment-system" v-if="item.type==3">...</div>  <!-- 系统消息 -->
            <div class="every-comment-nologin" v-if="item.type==4">...</div>  <!-- 未登录提示 -->
            <div class="every-comment-banned" v-if="item.type==5">...</div>  <!-- 禁言通知 -->
        </div>
    </div>
</div>


<script>
export default {
    data() {
        return {
            commentValue: "",  //评论内容
            commentList: [],  //聊天列表
            liveSocket: null,  //socket实例
            isSocketOpen: false,  //socket是否打开
            pingpangTimer: null,  //socket心跳计数器
        };
    },
    deactivated(){
        clearInterval(this.pingpangTimer)
        this.liveSocket?.close()
    },
    beforeDestroy(){
        clearInterval(this.pingpangTimer)
        this.liveSocket?.close()
    },
    created(){
        this.$eventBus.$on("liveInfo",(data)=>{
            this.liveInfo=data
            if(this.liveInfo?.wsUrl){  //socket链接由后端提供
                this.chatInit()  //初始化聊天
            }
        })
    },
    methods: {
        //初始化socket
        chatInit(){
            let socketlink=null
            if(this.userInfo.tokenValue){
                socketlink=`${this.liveInfo.wsUrl}?token=${this.userInfo.tokenValue}`
            }else{
                socketlink=this.liveInfo.wsUrl
            }
            this.commentList=[] //创建新的socket连接前先清除之前的实时聊天记录
            this.liveSocket?.close() //创建新的socket连接前确保旧的已关闭
            //创建一个socket实例
            this.liveSocket = new WebSocket(socketlink)
            //监听socket打开
            this.liveSocket.onopen = () => {
                this.isSocketOpen = true
                console.log('WebSocket连接已打开!');
            }
            //监听socket关闭
            this.liveSocket.onclose = () => {
                this.isSocketOpen = false
                console.log('WebSocket连接已关闭!');
            }
            //监听socket错误
            this.liveSocket.onerror = () => {
                this.isSocketOpen = false
                console.log('WebSocket连接打开失败');
            }
            //监听socket消息,不是调用形式,getComment后面不要加()
            this.liveSocket.onmessage = this.getComment

            //先确保清除了之前的心跳定时器
            clearInterval(this.pingpangTimer)
            //每过一段时间发送一次心跳,发送Ping,服务器会反馈pong,防止断连
            this.pingpangTimer = setInterval(() => {
                this.liveSocket.send("ping");
            },60000)

        },
        //监听socket消息
        getComment(res){
            let infos=JSON.parse(res.data)
            console.log(infos)
            // type类型:0-普通发言;1-管理员发言;2-欢迎提示;3-系统消息;4-未登录;5-禁言通知;6-ping;7-错误提示;8-初始会返回的整个聊天数据列表
            const allowType=[0,1,2,3,4,5]  //这些类型的数据将允许被推入聊天数据列表
            if(infos.type==8){
                this.commentList=this.commentList.concat(infos.list)  //需要取infos下的list,数据结构和后端商定
                let scrolltimer=setTimeout(()=>{  //自动滚动到底部
                    document.getElementById('comment-list').scrollTop=this.commentList.length*300  //偷懒了,较佛系的办法-_-,假定平均每条评论所占区域高度300。。。
                    clearTimeout(scrolltimer)
                },600)
            }else if(allowType.includes(infos.type)){  //后续每更新一条有效的新数据时触发(标准参考上面allowType)
                this.commentList=this.commentList.concat(infos)  //返回单个的聊天数据对象
                let scrolltimer=setTimeout(()=>{
                    document.getElementById('comment-list').scrollTop=this.commentList.length*300
                    clearTimeout(scrolltimer)
                },150)

                if(infos.type==4){  //未登录,清除用户信息和token
                    //do something
                }
                //......
            }else if(infos.type==7){  //出现错误
                //do something
            }
        },
        //发表评论
        sendComment(){
            if(this.commentValue==""){
                this.$message.info("说点什么吧 ~")
            }else if(this.commentValue.length>300){
                this.$message.info(`评论字数请勿超过200个字符,当前 ${this.commentValue.length}`)
            }else{
                if(this.userInfo.tokenValue){  //已登录
                    if(this.isSocketOpen){  //socket连接正常
                        // 如果后端规定了评论数据格式,则按照后端的传,注意socket.send需要传字符串,其他类型需要转下
                        // let theValue={
                        //     "ccontent":this.commentValue
                        // }
                        // let transedValue=JSON.stringify(theValue)
                        // this.liveSocket.send(transedValue);
                        this.liveSocket.send(this.commentValue)  //如果后端没规定,直接传评论内容即可
                        this.commentValue=""
                    }else{  //socket已断开
                        this.$message.info('聊天断开啦,请重新进入此页面尝试 ~')
                    }
                }else{  //未登录
                    this.$message.info("您尚未登录,请登录后再试")
                }
            }
        },
    }
}
</script>


<style scoped lang="less">
    .chat-content{
        width: 300px;
        height: 600px;
        .comment-list{
            width: 100%;
            height: 100%;
            padding: 20px 20px;
            box-sizing: border-box;
            overflow-y: auto;
            .every-comment{
                margin-bottom: 20px;
                .every-comment-user{
                    ......
                }
                .every-comment-admin{
                    ......
                }
                ......
            }
        }
    }
</style>

相关api

posted @ 2022-10-12 16:07  huihuihero  阅读(148)  评论(0编辑  收藏  举报