【uniapp+ts】 实现直播中 “聊天功能” 交互的组件封装和调用

示例图:

一、安装 @aspnet/signalr  包

npm install --save @aspnet/signalr

二、创建 signalR.ts 文件

代码如下: 

// 引入安装的signalr包<br>import * as signalR from '@aspnet/signalr'

import * as signalR from '@microsoft/signalr'


// 服务器地址——后台给的聊天流地址
let url = ''

const signal = new signalR.HubConnectionBuilder()
  .withUrl(url+'/IMHub', {
    skipNegotiation: true,
    transport: signalR.HttpTransportType.WebSockets
  })
  .configureLogging(signalR.LogLevel.Information)
  .build()

// 服务端掉线
signal.onclose(() => {
    console.log('服务器掉线')
    // Start()
	signal.off('ConnectMessage')
	signal.off('ReceiveMessage')
	signal.off('ReceiveCount')
})

//  自动重连
export function Start() {
  try {
    signal.start().then(() => {
      console.log('重连成功')
    }).catch(() => {
      setTimeout(() => Start(), 5000)
    })
  } catch (err) {
    console.log('重连失败', err)
    setTimeout(() => Start(), 5000)
  }
}

// 发送指令
export function SendMsg(type:any, actionObjectId:any, remark = '') {
  try {
    console.log(signal)
    // var userId = parseInt(store.getters.user.id)
    // signal.invoke('oper', { 1, type, actionObjectId, remark })
  } catch (e) {
    console.log('SendMsg')
  }
}

// 获取signalr实例
export function GetSignalr() {
  return signal
}

三、页面调用

<script lang="ts" setup>
import { GetSignalr } from '@/utils/signalR'

// 开启聊天流
GetSignalr().start()
// 添加聊天室——将你发送的信息以及相关参数上传到服务器
GetSignalr().on('ConnectMessage', () => {
     // 上传参数根据需要,后台配置的上传
     GetSignalr().invoke('AddToGroup', { userId:0, Message: '这是聊天内容' })
})
// 获取聊天记录
GetSignalr().on('ReceiveMessage', (Message: any) => {})

</script>

四、完整代码

<template>
	<view class="livePlay_right">
		<view class="user_chat">
			<strong v-for="item in person.Messages" :key="item" v-if="person.Messages.length>0">
				<view class="chat_left" v-if="!item.isMe">
					<view class="chat_ava">
						<span v-if="item.userType===1">主讲老师</span>
						<span v-if="item.userType===4">助教老师</span>
						{{item.userName}}
					</view>
					<view class="chat_txt">{{item.message}}</view>
				</view>
				<view class="chat_right_box">
					<view class="chat_right" v-if="item.isMe">
						<view class="chat_ava">
							{{ person.userInfo.Name?person.userInfo.Name:'——' }}
						</view>
						<view class="chat_txt">{{item.message}}</view>
					</view>
				</view>
			</strong>
			<view v-else class="user_chat_kong">暂无聊天记录</view>
		</view>
		<view class="input_quick flex" v-if="person.isShowQuick">
			<view class="input_quick_item flex" v-for="(quick,quickIndex) in person.quickList" :key="quickIndex" @click="SendQuick(quick)">
				<view v-if="quickIndex===0">
					<image src="@/static/newVer/4.svg" mode=""></image>
					<image src="@/static/newVer/4.svg" mode=""></image>
					<image src="@/static/newVer/4.svg" mode=""></image>
				</view>
				<text v-else>{{quick.name}}</text>
			</view>
		</view>
		<view class="input_initia" v-if="person.token&&person.userInfo">
			欢迎 {{ person.userInfo.Name?person.userInfo.Name:'——' }} 进入直播间👏
		</view>
		<view class="user_input" v-if="person.token">
			<view class="input_tool flex">
				<view class="input_tool_l flex">
					<input placeholder-style="color:#BDBDBD;" @input="inputKey" v-model="person.textarea" @focus="focusBtn" placeholder="说点什么..." clearable/>
				</view>
				<view class="input_tool_r flex">
					<view class="tool_item" @click="SendFlower">
						<image src="@/static/newVer/flower_icon.png" mode=""></image>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script lang="ts" setup>
import { reactive, watchEffect } from 'vue'
import { GetSignalr } from '@/utils/signalR'
import { onShow,onUnload} from "@dcloudio/uni-app";

let person:any=reactive({
	materialInfo:{}, // 详情
	IsCollect: 0,
	obj:{},
	userInfo:{},
	token:'',
	Messages:[
		// {message:'欢迎同学们',isMe:false}
	], // 聊天列表
	textarea:'',
	quickList:[
		{name:'👍👍👍'},
		{name:'讲得好'},
		{name:'很有收获'}
	],
    isShowQuick:false
})

// 刷新加载时的处理
onShow(()=>{
	scrollTop()
	enterEvent()
})

// 退出当前页面关闭聊天流
onUnload(()=>{
	GetSignalr().invoke('RemoveNum', { NodeId: person.NodeId, DetailId: person.Id, UserId: person.userInfo.Id??0 })
})

GetSignalr().start()
watchEffect(() => {
   GetSignalr().on('ConnectMessage', () => {
     // 添加聊天室
     GetSignalr().invoke('AddToGroup', { NodeId: person.NodeId, DetailId: person.Id, UserId: person.userInfo.Id??0, userName: person.userInfo.Name??'',userType:person.userInfo.UserType??0 })
   })
   // 监听前往更新任务列表
   GetSignalr().on('ReceiveMessage', (Message: any) => {
	    if (Message.userId !== person.userInfo.Id) {
	       Message.isMe = false
	       person.Messages.push(Message)
	    } else {
	       Message.isMe = true
	       person.Messages.push(Message)
	    }
   })
})
// 发送快捷键
const SendQuick=(item:any)=>{
	GetSignalr().invoke('HandMessage', { NodeId: person.NodeId, DetailId: person.Id, UserId: person.userInfo.Id??0, userName: person.userInfo.Name ?? '',userType:person.userInfo.UserType??0,Message:item.name })
	scrollTop()
	person.isShowQuick=false
}
// 移动端回车按钮
const enterEvent=()=>{
    document.onkeydown = e =>{
		if (e.keyCode === 13) {
			SendMsg()
		}
	}
}

// 送花
const SendFlower=()=>{
	GetSignalr().invoke('HandMessage', { NodeId: person.NodeId, DetailId: person.Id, UserId: person.userInfo.Id??0, userName: person.userInfo.Name ?? '',userType:person.userInfo.UserType??0,Message:'送出小花 🌹' })
	scrollTop()
}

// 发送消息
let SendMsg=()=>{
	GetSignalr().invoke('HandMessage', { NodeId: person.NodeId, DetailId: person.Id, UserId: person.userInfo.Id??0, userName: person.userInfo.Name ?? '',userType:person.userInfo.UserType??0,Message:person.textarea })
    person.textarea=''
    scrollTop()
	person.isShowQuick=false
}

// 发送信息后,聊天信息定位到最后一条
let scrollTop=()=>{
    setTimeout(()=>{
        const remFlag = document.getElementsByClassName("user_chat")[0]
		if(remFlag){
           remFlag.scrollTop = remFlag.scrollHeight
		}
    },200)
}
</script>

<style lang="scss" scoped>
// 讨论
.livePlay_right{
    color: #F5F8FA;
    .user_chat::-webkit-scrollbar{
        width: 0;
    }
    .user_chat{
        height:calc(100vh - 400px);
        overflow-y: scroll;
        padding: 20rpx 0 0 0;
        border-right: 0;
        border-left: 0;
        .user_chat_kong{
            width: 100%;
            height: 100%;
            display: flex;
            flex-direction: column;
            justify-content: center;
            text-align: center;
            font-size: 28rpx;
        }
        .chat_left{
            margin-bottom: 15px;
            position: relative;
			background: #000;
			border-radius: 40rpx;
			padding: 24rpx;
			width:70%;
            .chat_ava{
                color: #8797A2;
                font-size: 14px;
                span{
                    background: #2080F7;
                    border-radius: 5px;
                    color: #fff;
                    font-size: 12px;
                    padding: 2px 5px;
                    margin-right: 5px;
                    font-weight: 400;
                }
            }
            .chat_txt{
                font-weight: 400;
                font-size: 32rpx;
                padding: 20rpx 0;
            }
        }
		.chat_right_box{
			width: 100%;
			display: flex;
			justify-content: flex-end;
			.chat_right{
				width: 70%;
			    margin-bottom: 30rpx;
				background: #000;
				border-radius: 40rpx;
				padding: 24rpx;
			    .chat_ava{
			        color: #8797A2;
			        font-size: 28rpx;
					text-align: right;
			    }
			    .chat_txt{
			        font-weight: 400;
			        font-size: 32rpx;
			        padding: 20rpx 0px;
			        text-align: right;
			    }
			}
		}
    }
	// 欢迎初始化进入
	.input_initia{
		position: fixed;
		bottom: 130rpx;
		left: 35rpx;
		font-size: 28rpx;
		display: none;
	}
	.input_initia_ani{
		animation: toLeft .3s linear both;
	}
	.input_initia_block{
		display: block;
	}
	.input_initia_none{
		display: none;
	}
	@keyframes toLeft {
		from {
			left: 35rpx;
			opacity: .8;
		}
		to {
			left: -300rpx;
			opacity: 0;
		}
	}
	// 快捷语
	.input_quick{
		position: fixed;
		bottom: 140rpx;
		left: 0;
		width: 100%;
		padding: 10rpx 30rpx 0 30rpx;
		.input_quick_item{
			font-size: 28rpx;
			padding: 10rpx 30rpx;
			background: #464B4F;
			border-radius: 100rpx;
			margin-right: 20rpx;
			image{
				width: 30rpx;
				height: 30rpx;
				margin-right: 10rpx;
			}
			image:last-child{
				margin-right: 0;
			}
		}
	}
    :deep(.user_input){
        background: #1B2128;
		position: fixed;
		bottom: 0;
		left: 0;
		width: 100%;
		border-top: 2rpx solid #000;
        .input_tool{
            cursor: pointer;
            justify-content: space-between;
            padding: 20rpx 32rpx;
			.input_tool_l{
				background: #000;
				border-radius: 100rpx;
				padding: 18rpx 34rpx;
			}
            .input_tool_r{
				.tool_item{
					width: 74rpx;
					height: 74rpx;
					line-height: 74rpx;
					background: #000;
					border-radius: 50%;
					text-align: center;
					margin-left: 35rpx;
				}
                image{
					margin: 15rpx auto 0 auto;
					width: 30rpx;
					height: 40rpx;
                }
            }
        }
        .user_input_box{
            padding: 40rpx;
        }
        .el-textarea__inner::-webkit-scrollbar{
            width: 0;
        }
        .el-textarea__inner{
            font-size: 36rpx;
            border: 0;
            background: inherit;
            box-shadow: inherit;
            color: #F5F8FA;
        }
        .user_input_btn{
			font-size: 28rpx;
            width: 100rpx;
            text-align: right;
			white-space: nowrap;
        }
    }
}
</style>

       希望我的愚见能够帮助你哦~,若有不足之处,还望指出,你们有更好的解决方法,欢迎大家在评论区下方留言支持,大家一起相互学习参考呀~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值