前面介绍了【Laravel中Websocket基本使用(Workerman)】 基于workman的基础上实现了【uni-app php workman实现简单聊天功能之API开发】、【uni-app php workman实现简单聊天功能之聊天模块封装】 接下来完成前后端交互,本文只介绍主要页面和主要代码 我们涉及到的页面有主要两个
- 消息列表页
- 消息详情页
msg.vue
<template>
<view>
<!-- 消息列表 -->
<template v-if="list.length>0">
<block v-for="item,index in list" :key="index">
<msg-list :item="item" :index="index"></msg-list>
</block>
</template>
<view>
<template>
代码语言:javascript复制<script>
import msgList from "@/components/msg/msg-list.vue"
export default {
components:{msgList},
data() {
return {
firstload:false,
show:false,
list:[]
}
},
onShow(){
//获取消息列表
this.getdata()
console.log(this.list)
},
onLoad() {
//监听消息
uni.$on('UserChat',data=>{
//将最新消息置顶更新
let index = this.list.findIndex(val=>{
return val.userid === data.from_id;
});
//如果当前会话存在则更新时间、内容、未读数,并进行置顶
if(index!==-1){
this.list[index].data = data.data
this.list[index].time = data.time
this.list[index].noreadnum ;
//置顶
this.list = this.$chat.__toFirst(this.list,index)
return
}
//如果当前会话不存在--新消息 则将当前消息追加到消息列表最前面
let obj = this.$chat.__format(data,{type:"chatlist"});
obj.noreadnum=1;
this.list.unshift(obj);
})
},
methods: {
getdata(){
try{
let userid = User.userinfo.id;
if(!userid) return this.firstload = true;
this.list = [];
let list = uni.getStorageSync('chatlist' userid)//获取消息列表
list = list?JSON.parse(list):[];
this.list = list;//添加到消息列表
}catch(e){
uni.showToast({
title: '加载失败~',
icon:'none'
});
}
this.firstload = true;
}
...
在页面初始化的时候,我们调用getdata
获取消息列表数据,从本地存储中取到,因为我们在收到消息的时候会将其存储到本地存储,并进行未读消息的统计。可参照前面【uni-app php workman实现简单聊天功能之聊天模块封装】 同时本页面还监听消息事件,当收到消息的时候,对最新消息进行置顶 本页面使用了msgList
组件
<template>
<view class="flex align-center p-2 border-bottom animate__animated animate__fast animate__fadeIn" @click="open">
<image :src="item.userpic" style="height: 80rpx;width: 80rpx;"
class="rounded-circle mr-2">
</image>
<view class="flex flex-column flex-1">
<view class="flex align-center justify-between">
<text class="font-md">{{item.username}}</text>
<text class="font font-sm text-secondary">{{item.time}}</text>
</view>
<view class="flex align-center justify-between">
<text class="text-secondary text-ellipsis" style="max-width: 500rpx;">
{{item.data}}
</text>
<uni-badge :text="getItemNoreadnum" type="error" v-if="getItemNoreadnum"></uni-badge>
</view>
</view>
</view>
</template>
<script>
import uniBadge from "@/components/uni-ui/uni-badge/uni-badge.vue"
export default{
components:{
uniBadge
},
//接受聊天数据
props:['item'],
methods:{
open(){
uni.navigateTo({
"url":"../../pages/user-chat/user-chat?userinfo=" JSON.stringify({
userid:this.item.userid,
username:this.item.username,
userpic:this.item.userpic
})
})
this.$chat.Read(this.item)//更新未读数据
}
},
computed:{
getItemNoreadnum(){
return this.item.noreadnum
}
}
}
...
该组件主要实现列表消息渲染和跳转操作,消息未读清零 当消息列表被点击时,会跳转到消息详情页并传递对方用户的相关参数,在进行调用chat模块的Read
进行消息清零操作 效果图展示
user-chat
<template>
<view>
<!-- 聊天列表 -->
<scroll-view scroll-y="true"
style="position: absolute;left:0;top:0;right:0;bottom: 100rpx;"
:scroll-into-view="scrollInfo" scroll-with-animation>
<block v-for="item,index in list" :key="index">
<view :id="'chat' index">
<!-- 头像一直左上方 | 左边 | 如果不是第一条消息传入上一次消息时间-->
<user-chat-list v-if="!item.isme" :item="item" :index="index " :pretime="index>0?list[index-1].create_time:0"></user-chat-list>
</view>
<!-- 右边 -->
<view v-if="item.isme" class="flex align-start px-2" style="flex-direction: row-reverse;">
<image :src="item.userpic" style="width:100rpx;height:100rpx" class="rounded-circle">
<view class="bg-light p-2 rounded mx-2" style="min-width: 200rpx;max-width: 400rpx;">
{{item.data }}{{item.userid}}
</view>
</image>
</view>
</block>
</scroll-view>
<bottom-input @submit="submit"></bottom-input>
</view>
</template>
代码语言:javascript复制export default {
components:{
userChatList,bottomInput
},
data() {
return {
scrollInfo:"",
scrollH:500,
focus:true,
loadtext:'加载更多',
list:[]
}
},
onLoad(e){
//获取发送方用户信息
let userinfo = JSON.parse(e.userinfo)
//没有该用户
if(!userinfo.userid){
uni.showToast({
title: '该用户不存在',
icon:'none'
});
return uni.navigateBack({
delta:1
})
}
//设置当前聊天对象
this.$chat.CurrentToUser = {
userid:userinfo.userid,
username:userinfo.username,
userpic:userinfo.userpic
}
//修改导航标题
uni.setNavigationBarTitle({
'title':userinfo.username
})
},//退出聊天的时候
onUnload() {
//初始化聊天对象
this.$chat.CurrentToUser = {
userid:0,
username:"",
userpic:"",
}
},
onReady(){
this.__init()
},
methods: {
//接受聊天数据(首次只获取10条数据)
async getdata(isall = false){
try{
let key = 'chatdetail_' this.User.userinfo.id '_' this.$chat.CurrentToUser.userid;
//获取聊天记录
let list = uni.getStorageSync(key);
// console.log(list)
list = list?JSON.parse(list):[];
//首次加载10条
if(!isall && list.length>10){
return this.list = list.splice(0,10);
}
//加载剩下的数据
this.list = list;
this.loadtext = '';
}catch(e){
uni.showToast({
title:'加载失败',
icon:'none'
})
}
},
submit(data){
//发送消息
let obj = this.$chat.Send({'type':'text','data':data,'isme':true});
console.log(obj)
this.$.post('chat/send',{
'to_id':this.$chat.CurrentToUser.userid,
'from_userpic':'https://cdn.learnku.com/uploads/images/201710/14/1/s5ehp11z6s.png',
'type':'text',
'data':data
},{
header: {
'Accept':'application/json',
'Authorization':'Bearer ' uni.getStorageSync('access_token')
}
}).then(res=>{
console.log(res)
console.log('发送完毕')
//错判断
//成功处理
// return this.resultUserBind(res.data.data)
})
this.list.push(obj)
this.pageToBottom()
},
//滚动底部
pageToBottom(){
let lastIndex = this.list.length-1
if(lastIndex<0)return;
this.scrollInfo = 'chat' lastIndex
},
//初始化参数
__init(){
//获取窗口消息
try{
const res = uni.getSystemInfoSync();
this.scrollH = res.windowHeight-uni.upx2px(101);
}catch(e){
}
//获取聊天历史记录
this.getdata();
//至于底部
this.pageToBottom()
//监听消息
uni.$on('UserChat',data=>{
this.list.push(this.$chat.__format(data,{
type:'chatdetail',
isme:false,
olddata:this.list
}));
this.pageToBottom()
console.log('监听到数据')
// console.log(data)
})
}
}
}
</script>
消息详情页加载的时候首先对聊天用户进行了初始化,保存在chat
模块,然后调用初始化函数__init()
该函数用于
- 设置内容滚动高度
- 获取聊天记录
- 监听消息,对消息存储(chat模块),最新消息展示
当发送消息时,调用chat
模块的Send
函数,进行数据格式,数据存储等 然后在发送ajax与服务器进行交互 服务端拿到数据后首先判断接收方用户是否在线,如果在线则转发,不在线则存储到缓存
public function send(ChatRequest $request){
// 1. 验证数据是否合法
// 2. 组织数据
$data = $this->resdata($request);
// return response()->json($data);
$to_id = $request->to_id;
// 3. 验证对方用户是否在线
if (Gateway::isUidOnline($to_id)) {
// 直接发送
Gateway::sendToUid($to_id,json_encode($data));
// 写入数据库
// 返回发送成功
return $this->showResCodeWithOutData('ok');
}
// 不在线,写入消息队列
// 获取之前消息
$Cache = Cache::get('userchat_'.$to_id);
if (!$Cache || !is_array($Cache)) $Cache = [];
$Cache[] = $data;
// 写入数据库
// 写入消息队列(含id)
Cache::set('userchat_'.$to_id,$Cache);
return $this->showResCodeWithOutData('ok');
}
效果展示