前言
上一篇讲到了如何布局,这一篇将讲一下如何用uni-app实现小程序聊天页面的最主要的功能——发消息后页面滚动到最底部(参考过很多文章最后找到比较适合的方法)。
其他的功能(参考微信),之后的文章会讲述到具体实现方法
- 点击聊天框的时候,聊天框随键盘抬起且聊天消息列表滚动到最底部,但整体页面不抬起
- 聊天框textarea根据内容自适应高度,且聊天消息列表随着聊天框的增高而滚动到最底部(说白了就是最底部的消息不会被增高的聊天框给挡住)
思路
由于我们在布局上聊天滚动用的是scroll-view
,里面嵌套着一个存放消息列表的容器(如左图所示),scroll-view中的一个重要属性是scroll-top
,官方文档解释设置竖向滚动条位置。
当消息列表的长度超过scroll-view的高度时,它们之间的高度差就是scroll-view要滚动的距离(如右图所示)。
获取节点信息用boundingClientRect
这个函数,具体方法可以参考官网uni.createSelectorQuery() | uni-app官网 (dcloud.net.cn)
坑
原本js部分的代码是这样写的:
scrollToBottom(){
let query = uni.createSelectorQuery().in(this);
// 获取节点信息
query.select('#scrollview').boundingClientRect();
query.select('#msglistview').boundingClientRect();
query.exec((res) =>{
if(res[1].height > res[0].height){
this.scrollTop = res[1].height - res[0].height
}
})
},
但是,在实测时(小程序模拟器和真机)发现滚动的位置有时滚动不到最底部(如图所示,其实下面还有一条消息被遮住了没显示出来),有时又可以滚动到最底部。
初步怀疑是节点信息获取不准确,我就去搜了关于boundingClientRect()
这个函数的相关信息,官方文档上并没有对这个问题的解释,后来找到解决方案
参考文章:微信小程序 boundingClientRect 获取元素节点位置信息不准确_LGDmar的博客-CSDN博客
问题所在:页面未渲染完成而去获取了节点信息
解决方案:
方法一:可以设置一个延时函数setTimeout
,因为我们不知道渲染的时间是多少,所以我是经过试验得出一个满足需求的延时时间。
// 滚动至聊天底部
scrollToBottom(){
// 外层加一个延时函数是为了能获取到节点的准确信息
setTimeout(()=>{
let query = uni.createSelectorQuery().in(this);
// 获取节点信息
query.select('#scrollview').boundingClientRect();
query.select('#msglistview').boundingClientRect();
query.exec((res) =>{
if(res[1].height > res[0].height){
this.scrollTop = this.rpxTopx(res[1].height - res[0].height)
}
})
},15)
},
方法二:
使用$nextTick
,意为在下次DOM更新完之后执行一个回调函数。文章来源:https://www.toymoban.com/news/detail-500884.html
//滚动至聊天底部
scrollToBottom(){
let query = uni.createSelectorQuery().in(this);
//获取节点信息
query.select('#scrollview').boundingClientRect();
query.select('#msglistview').boundingClientRect();
query.exec((res) =>{
if(res[1].height > res[0].height){
this.$nextTick(()=>{
this.scrollTop = this.rpxTopx(res[1].height - res[0].height)
})
}
})
},
代码实现
vue页面:
(如果需要参考css部分,请看我发布的上篇文章布局篇)文章来源地址https://www.toymoban.com/news/detail-500884.html
<template>
<view class="chat">
<scroll-view :style="{height: `${windowHeight}rpx`}"
id="scrollview"
scroll-y="true"
:scroll-top="scrollTop"
:scroll-with-animation="true"
class="scroll-view"
>
<!-- 聊天主体 -->
<view id="msglistview" class="chat-body">
<!-- 聊天记录 -->
<view v-for="(item,index) in msgList" :key="index">
<!-- 自己发的消息 -->
<view class="item self" v-if="item.userContent != ''" >
<!-- 文字内容 -->
<view class="content right">
{{item.userContent}}
</view>
<!-- 头像 -->
<view class="avatar">
</view>
</view>
<!-- 机器人发的消息 -->
<view class="item Ai" v-if="item.botContent != ''">
<!-- 头像 -->
<view class="avatar">
</view>
<!-- 文字内容 -->
<view class="content left">
{{item.botContent}}
</view>
</view>
</view>
</view>
</scroll-view>
<!-- 底部消息发送栏 -->
<!-- 用来占位,防止聊天消息被发送框遮挡 -->
<view class="chat-bottom">
<view class="send-msg">
<view class="uni-textarea">
<textarea v-model="chatMsg"
maxlength="300"
:show-confirm-bar="false"
auto-height></textarea>
</view>
<button @click="handleSend" class="send-btn">发送</button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
//滚动距离
scrollTop: 0,
userId:'',
//发送的消息
chatMsg:"",
msgList:[
{
botContent: "hello,请问我有什么可以帮助你的吗?",
recordId: 0,
titleId: 0,
userContent: "",
userId: 0
},
{
botContent: "",
recordId: 0,
titleId: 0,
userContent: "你好呀我想问你一件事",
userId: 0
},
]
}
},
computed: {
windowHeight() {
return this.rpxTopx(uni.getSystemInfoSync().windowHeight)
}
},
methods: {
// px转换成rpx
rpxTopx(px){
let deviceWidth = wx.getSystemInfoSync().windowWidth
let rpx = ( 750 / deviceWidth ) * Number(px)
return Math.floor(rpx)
},
//滚动至聊天底部
scrollToBottom(){
//外层加一个延时函数是为了能获取到节点的准确信息
setTimeout(()=>{
let query = uni.createSelectorQuery().in(this);
//获取节点信息
query.select('#scrollview').boundingClientRect();
query.select('#msglistview').boundingClientRect();
query.exec((res) =>{
if(res[1].height > res[0].height){
this.scrollTop = this.rpxTopx(res[1].height - res[0].height)
}
})
},15)
},
// 发送消息
handleSend() {
//如果消息不为空
if(!this.chatMsg||!/^\s+$/.test(this.chatMsg)){
let obj = {
botContent: "",
recordId: 0,
titleId: 0,
userContent: this.chatMsg,
userId: 0
}
this.msgList.push(obj);
this.chatMsg = '';
}else {
this.$modal.showToast('不能发送空白消息')
}
},
}
}
</script>
到了这里,关于【uni-app】uni-app实现聊天页面功能——功能篇(上)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!