示例图:
一、安装 @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>
希望我的愚见能够帮助你哦~,若有不足之处,还望指出,你们有更好的解决方法,欢迎大家在评论区下方留言支持,大家一起相互学习参考呀~