app.vue页面
里面的message.type 是和后台商量的类型。
1. websocket是进小程序就要启动的,在onLaunch里面但是肯定是在用户登录之后才启动,不然要报错。
2. 在onShow里面监听了一个emit,在用户登录之后,要启动websocket。
index.vue 聊天列表页面
这里就会监听到newSocketMsg,一监听到就会获取列表数据,包括聊天数目,遍历在列表上。
HTML部分代码:聊天列表
{{item.to_user_info.nickname}}
{{$u.timeFrom(item.last_message.created_at, 'yyyy-mm-dd')}}
{{item.last_message.message}}
js代码
data() {
return {
loading: false,
chatData: [],
message: null, // 服务器返回对象
status: 'loadmore',
list: 0,
page: 0,
}},
onLoad() {
// 登录后刷新页面
uni.$on('refresh', () => {
this.getList(true)
})
// 接收到socket
uni.$on('newSocketMsg', (data) => {
this.message = data
this.initState()
})
},
/**
* 初始化
*/
initState(init) {
let message = this.message
switch(message.type) {
case 'letters':
this.getList(true);
break;
default:
break;
}
},
/**
* @param {Object} init 获取列表
*/
getList(init) {
if(init) {
this.page = 1
}
this.$u.api.Meet.friendsList({
page: this.page
}).then(res => {
if(res) {
this.page = res.page
this.total = res.totalPage
this.chatData = init ? res.list : this.chatData.concat(res.list)
if(this.page >= this.total) this.status = 'nomore';
else this.status = 'loading';
}
setTimeout(() => {
this.loading = false;
}, 500)
}).catch(e => {
setTimeout(() => {
this.loading = false;
}, 500)
console.error(e)
})
},
chat.vue 聊天页面
这里只展示跟websocket相关的代码,主要是接收消息和发送消息,注意我这里获取历史消息是一进页面就开始访问了接口;发送消息也是先调接口,毕竟数据要存在数据库,下次获取历史消息才有,后才通过websocket发送消息展示在页面上。
onLoad() {
// 这里监听app.vue存的emit,初始化方法
uni.$on('newSocketMsg', (data) => {
this.message = data
this.initMethod()
})
},
onShow() {
// 拿聊天记录
this.getHistoryMsg();
// 点对点聊天判断对方是否在线
let online = {
type: 'online',
to_id: this.toUser.id,
from_id: this.userid
}
this.$store.state.wss.send({
data: JSON.stringify(online)
});
},
methods: {
initMethod() {
let message = this.message
switch(message.type) {
case 'init':
console.log('init')
break;
case 'text':
console.log(message)
let text = {
id: message.id,
from_id: message.from_id,
to_id: message.to_id,
content: message.data,
type: 0,
text: message.type, // 表示文本信息(后台)
is_read: message.is_read,
pic: this.baseImgUrl + this.toUser.pic
}
this.talkList.push(text)
this.$nextTick(()=>{
uni.pageScrollTo({
scrollTop: 999999, // 设置一个超大值,以保证滚动条滚动到底部
duration: 0
});
})
break;
case 'online':
// 用户在线不在线, 涉及到一些业务场景需要处理
// 如果对方上线了, 后端也会主动推送到这个里面来
console.log('online:', message)
break;
}
},
// 发送信息
send(){
if(!this.content){
uni.showToast({
title:'请输入有效的内容',
icon:'none'
})
return;
}
uni.showLoading({
title:'正在发送'
})
let head_image = uni.getStorageSync('userInfo').avatar_url
let timeStame = new Date().getTime()
// 将当前发送信息 添加到消息列表。
let data = {
id: timeStame,
content: this.content,
type: 1, // 1: 发送的
pic: head_image.includes('http://') ? head_image : this.baseImgUrl + head_image
}
// 发送 调接口
this.$u.api.Meet.chatWithOneFriend({
to_id: this.toUser.id,
message: this.content,
// 类型: 0未读,1已读, 双方处于在线聊天中, 直接就是已读,对方不在线,就是未读
is_read: this.message ? this.message.type == 'online' ? this.message.status.includes('对方不在线') ? 0 : 1 : 0 : 0
}).then(res => {
uni.hideLoading();
// 页面显示
this.talkList.push(data);
this.$nextTick(()=>{
// 清空内容框中的内容
this.content = '';
// 滚动到最新一条数据
uni.pageScrollTo({
scrollTop: 999999, // 设置一个超大值,以保证滚动条滚动到底部
duration: 0,
});
})
}).catch(e => {
uni.hideLoading();
})
this.$store.state.wss.send({
data: JSON.stringify({
data: this.content,
type: 'say',
from_id: this.userid,
to_id: this.toUser.id
})
})
}
}