系统分析设计期末大项目——闲得一币TimeForCoin小程序前端
小程序项目地址_闲得一币
概述
实时会话系统包括两大部分:消息管理系统和会话系统。其中“消息”可以定义为一系列会话(即双方之间会话)的集合。通过获取消息列表,我们可以看到很多个消息,每一个消息都有对应的消息id。而通过消息的id,我们可以获取一系列会话,如下:
消息管理页
消息管理页将获取的消息分为个人消息以及系统消息。系统消息不能够被回复而个人消息可以。
在Message.json
中我们需要添加:"enablePullDownRefresh": true
以允许下拉刷新。而对于下拉刷新,我们可以通过onPullDownResfresh()
函数实现。除此之外,我们还需要在onShow
函数中添加信息获取的功能(还要有登录状态的判断)。
onShow函数
onShow: async function() {
this.setData({
hasUserInfo: app.globalData.hasUserInfo
})
//登录判断
if (!this.data.hasUserInfo) {
wx.showToast({
title: '您未登录~',
image: '/images/icons/error.png'
})
setTimeout(function() {
// 返回
wx.switchTab({
url: '/pages/index/index',
success: function(res) {
},
fail: function(res) {
},
complete: function(res) {
},
})
}, 1000);
}
await this.loadMessage(1)
},
onPullDownRefresh函数
onPullDownRefresh: async function () {
if(!this.data.isLoading){
await this.loadMessage(null)
}
},
至于为什么是onShow
而不是onLoad
,因为onShow
函数在你离开该页面重新进入(可以通过onNavigateBack
返回)该页面的时候也会执行一次。消息的状态包括未读
和已读
,如果使用onLoad
函数从会话列表页面返回时未读
不会更新为已读
。
在获取消息的函数loadMessage
内,我们需要进行https
请求,并根据请求的结果(状态码以及数据)进行消息的显示。如果状态码不为200
,需要进行异常处理,这里是显示toast。而对于获取的消息,我们根据当前用户选择的是个人消息还是系统消息进行分类,如果选择个人消息就只显示个人消息。除此之外,还需要moment.js
进行时间数据的解析。当然,除了时间,所有的数据都要进行正确显示。
当然了,这是个异步函数,因为其中需要等待https
请求的结果。
消息页比较有挑战性的是自动刷新ScrollView
到底端,使得有新的信息来的时候会自动显示。
loadMessage函数
loadMessage: async function(page) {
this.setData({
isLoading: true
})
if(page != null){
this.data.currentPage = page
this.data.systemMessage = []
this.data.chatMessage = []
} else{
this.data.currentPage++
}
const res = await server.request('GET', 'messages',{
page: this.data.currentPage,
size: 10
})
this.setData({
isLoading :false
})
if(res.statusCode !== 200){
this.setData({
hasUserInfo: false})
wx.showToast({
title: '网络错误',
icon: '',
image: '/images/icons/error.png',
duration: 0,
mask: true,
success: function(res) {
},
fail: function(res) {
},
complete: function(res) {
},
})
this.setData({
noMore: true
})
return
}
if(!res.data.data || res.data.data.length === 0){
this.setData({
noMore: true})
this.data.currentPage--
return
}
moment.locale('en', {
longDateFormat: {
l: "YYYY-MM-DD",
L: "YYYY-MM-DD HH:mm"
}
})
for (let i in res.data.data) {
res.data.data[i].string_last_time =
moment(res.data.data[i].last_message.time * 1000).format('L');
if (res.data.data[i].target_user.nickname.length > 10) {
res.data.data[i].target_user.nickname = res.data.data[i].target_user.nickname.substr(0, 10) + '...'
}
if (res.data.data[i].type === 'chat') {
this.data.chatMessage.push(res.data.data[i])
} else {
res.data.data[i].target_user.avatar = '/images/icon.png'
this.data.systemMessage.push(res.data.data[i])
}
}
if(!this.data.showSystemInfo){
this.setData({
testMessage: {
data: this.data.chatMessage
}
})
} else{
this.setData({
testMessage:{
data: this.data.systemMessage
}
})
}
},
当然,我们还需要添加单击事件。在标签中添加对应的data-item
为消息id,之后根据对应的消息id进行跳转(到会话列表中)。
// 跳转详情
navigateToMessageDetail: function(e) {
var id = e.currentTarget.dataset.id;
wx.navigateTo({
url: '/pages/MessageDetail/MessageDetail?session_id=' + id + '&status=message',
})
},
会话列表页
在会话列表页中,根据消息id进行会话列表的获取。
获取新会话
通过setTimeOut
实现定时获取新消息。当然与其他数据一样,列表是分页进行获取的。但与其他数据不同,越接近底部会话的时间是更新的,而通过api获取的页面下标越小是越新的,所以通过调用reverse
函数实现反转。如果获取多个页面,还需要进行反转后叠加。
if(isMore){
var arr = []
res.data.messages = res.data.messages.reverse()
for(var val of res.data.messages){
arr.push(val)
}
for(var val of this.data.testMessageDetail.data){
arr.push(val)
}
if(res.data.type !== 'chat'){
// 系统消息不进行整点判断
for (var i = 0; i < arr.length; i = i + 1) {
arr[i].string_time = moment(arr[i].time * 1000).format('L');
arr[i].showTime = true;
}
时间的解析
与之前的时间解析不同,如果对于每一条会话的时间都进行显示,就显得特别繁琐和难看了。这里模仿微信,在每一分钟才进行一次的会话时间的显示。这就需要判断每两个会话之间的时间差是否大于一分钟的。除此之外,第一条会话一定要显示其时间,否则用户无从判断。
实现如下:
// 用于时间显示
moment.locale('zh-cn', {
longDateFormat: {
l: "YYYY-MM-DD",
L: "YYYY-MM-DD HH:mm"
}
})
...
// 系统消息不进行整点判断
for (var i = 0; i < arr.length; i = i + 1) {
arr[i].string_time = moment(arr[i].time * 1000).format('L');
arr[i].showTime = true;
}
} else{
// 整点判断
for (var i = 0; i < arr.length - 1; i = i + 1) {
if ((arr[i + 1].time - arr[i].time) > 60 || i === 0) {
arr[i].string_time = moment(arr[i].time * 1000).format('L');
arr[i].showTime = true;
}
}
}
this.setData({
testMessageDetail: {
data: arr
},
});
判断自己和对方
这里通过全局变量中的用户id进行己方和对方的判断。如果是对方则显示白底黑字,而己方则显示主题色底和白色字。己方在右边而对方在左边。通过两个不同的view
标签并且通过wx:if
实现这种效果。
<view wx:if="{
{!item.self}}" style="display:flex; flex-direction: row; padding: 10rpx 30rpx; margin-top: 20rpx; width: 100%">
<image class="ava" src="{
{item.target_user.avatar}}" />
<view class="details">
<text class="username" style="text-align:left;">{
{item.target_user.nickname}}</text>
<text class="content" style=" opacity: 0.8;max-width:70%;">{
{item.content}}</text>
</view>
</view>
<view wx:if="{
{item.self}}" style="display:flex; flex-direction: row; padding: 10rpx 30rpx; margin-top: 20rpx;justify-content:flex-end;">
<view class="details" style="align-items:flex-end;">
<text class="username" style="text-align:right;">{
{item.target_user.nickname}}</text>
<text class="content" style="background-color:#ff7e67; color:white;">{
{item.content}}</text>
</view>
<image class="ava" src="{
{item.target_user.avatar}}" />
</view>
</view>
}
// 记录会话ID
this.data.session_id = res.data.id
this.data.status = 'message'
this.data.target_user_id = res.data.target_user.id
for (let i in res.data.messages) {
if (res.data.messages[i].user_id === res.data.target_user.id) {
res.data.messages[i].target_user = res.data.target_user
res.data.messages[i].self = false
} else {
res.data.messages[i].target_user = {
nickname: app.globalData.userInfo.info.nickname,
avatar: app.globalData.userInfo.info.avatar
}
res.data.messages[i].self = true
}
}
自动获取新消息
这里通过setTimeOut
实现循环获取消息,延时设为5s,避免过多的请求。在每一次获取新消息后,都需要将ScrollView
调整到最底部。下面会叙述其方法。
自动获取消息的时候,与第一次获取类似,只获取第一页,历史记录的获取使用触顶触发。
autoLoadMessage: async function(){
var res = await server.request('GET', 'messages/' + this.data.session_id, {
page: 1,
size: 1
})
if(res.data.length === 0) {
}
else{
var last = this.data.testMessageDetail.data[this.data.testMessageDetail.data.length - 1]
var getLast = res.data.data.messages[0]
if (getLast.content === last.content && getLast.time === last.time){
}else{
if (getLast.user_id === res.data.data.target_user.id) {
getLast.target_user = res.data.data.target_user
getLast.self = false
} else {
getLast.target_user = {
nickname: app.globalData.userInfo.info.nickname,
avatar: app.globalData.userInfo.info.avatar
}
getLast.self = true
}
moment.locale('en', {
longDateFormat: {
l: "YYYY-MM-DD HH:mm",
L: "YYYY-MM-DD HH:mm:ss"
}
})
getLast.string_time = moment(getLast.time * 1000).format('L')
getLast.showTime = false
this.data.testMessageDetail.data.push(getLast)
this.setData({
testMessageDetail:{
data: this.data.testMessageDetail.data
}
})
this.setData({
top_value: 100 * this.data.testMessageDetail.data.length,
})
}
// if (getLast.content === (this.data.testMessageDetail.data.reserve()[0]).content){
// }else{
// // this.data.testMessageDetail.data.push(res.data.data.)
// }
}
setTimeout(this.autoLoadMessage, 5000)
}
ScrollView与触顶触发
触顶触发中,wxml
使用如下:
<scroll-view bindscrolltoupper="onMsgRefresh" id="dialog_list" scroll-y="{
{true}}" scroll-with-animation='{
{true}}' scroll-top='{
{top_value}}'>
在onMsgRefesh
函数中,需要进行另一页面的获取,得到新的页面数据后,需要与之前的数据整合,并对整合后的数据进行时间显示的判断。
if (!this.data.isLoading && !this.data.noMore){
this.data.page = this.data.page + 1
this.loadMessage(this.data.session_id, this.data.status, true)
}
},
除此之外,当然还需要正在加载中
与没有更多
的显示。这里不多赘述。
ScrollView自动触底
这里需要考虑另外一个问题,新的会话已经获取,但是ScrollView
并没有滚动到最底部,新的消息被遮挡了。这就需要让ScrollView
滚动到最底部。对于这个标签,需要设定固定的大小,并且将scroll-top
双向绑定。在获取新的数据后,进行如下设定:
this.setData({
top_value: 100 * this.data.testMessageDetail.data.length,
})
去其中100
需要根据实际情况而设定。
底部对话栏
这个的实现与之前详情页的评论栏/回复栏类似,不多赘述,欢迎大家看我的另一篇博客(地址在最上面)。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/34530.html