前言
上一篇講到了如何布局,這一篇將講一下如何用uni-app實(shí)現(xiàn)小程序聊天頁(yè)面的最主要的功能——發(fā)消息后頁(yè)面滾動(dòng)到最底部(參考過(guò)很多文章最后找到比較適合的方法)。
其他的功能(參考微信),之后的文章會(huì)講述到具體實(shí)現(xiàn)方法
- 點(diǎn)擊聊天框的時(shí)候,聊天框隨鍵盤抬起且聊天消息列表滾動(dòng)到最底部,但整體頁(yè)面不抬起
- 聊天框textarea根據(jù)內(nèi)容自適應(yīng)高度,且聊天消息列表隨著聊天框的增高而滾動(dòng)到最底部(說(shuō)白了就是最底部的消息不會(huì)被增高的聊天框給擋?。?/li>
思路
由于我們?cè)诓季稚狭奶鞚L動(dòng)用的是scroll-view
,里面嵌套著一個(gè)存放消息列表的容器(如左圖所示),scroll-view中的一個(gè)重要屬性是scroll-top
,官方文檔解釋設(shè)置豎向滾動(dòng)條位置。
當(dāng)消息列表的長(zhǎng)度超過(guò)scroll-view的高度時(shí),它們之間的高度差就是scroll-view要滾動(dòng)的距離(如右圖所示)。
獲取節(jié)點(diǎn)信息用boundingClientRect
這個(gè)函數(shù),具體方法可以參考官網(wǎng)uni.createSelectorQuery() | uni-app官網(wǎng) (dcloud.net.cn)
坑
原本js部分的代碼是這樣寫的:
scrollToBottom(){
let query = uni.createSelectorQuery().in(this);
// 獲取節(jié)點(diǎn)信息
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
}
})
},
但是,在實(shí)測(cè)時(shí)(小程序模擬器和真機(jī))發(fā)現(xiàn)滾動(dòng)的位置有時(shí)滾動(dòng)不到最底部(如圖所示,其實(shí)下面還有一條消息被遮住了沒顯示出來(lái)),有時(shí)又可以滾動(dòng)到最底部。
初步懷疑是節(jié)點(diǎn)信息獲取不準(zhǔn)確,我就去搜了關(guān)于boundingClientRect()
這個(gè)函數(shù)的相關(guān)信息,官方文檔上并沒有對(duì)這個(gè)問(wèn)題的解釋,后來(lái)找到解決方案
參考文章:微信小程序 boundingClientRect 獲取元素節(jié)點(diǎn)位置信息不準(zhǔn)確_LGDmar的博客-CSDN博客
問(wèn)題所在:頁(yè)面未渲染完成而去獲取了節(jié)點(diǎn)信息
解決方案:
方法一:可以設(shè)置一個(gè)延時(shí)函數(shù)setTimeout
,因?yàn)槲覀儾恢冷秩镜臅r(shí)間是多少,所以我是經(jīng)過(guò)試驗(yàn)得出一個(gè)滿足需求的延時(shí)時(shí)間。
// 滾動(dòng)至聊天底部
scrollToBottom(){
// 外層加一個(gè)延時(shí)函數(shù)是為了能獲取到節(jié)點(diǎn)的準(zhǔn)確信息
setTimeout(()=>{
let query = uni.createSelectorQuery().in(this);
// 獲取節(jié)點(diǎn)信息
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更新完之后執(zhí)行一個(gè)回調(diào)函數(shù)。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-500884.html
//滾動(dòng)至聊天底部
scrollToBottom(){
let query = uni.createSelectorQuery().in(this);
//獲取節(jié)點(diǎn)信息
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)
})
}
})
},
代碼實(shí)現(xiàn)
vue頁(yè)面:
(如果需要參考css部分,請(qǐng)看我發(fā)布的上篇文章布局篇)文章來(lái)源地址http://www.zghlxwxcb.cn/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">
<!-- 自己發(fā)的消息 -->
<view class="item self" v-if="item.userContent != ''" >
<!-- 文字內(nèi)容 -->
<view class="content right">
{{item.userContent}}
</view>
<!-- 頭像 -->
<view class="avatar">
</view>
</view>
<!-- 機(jī)器人發(fā)的消息 -->
<view class="item Ai" v-if="item.botContent != ''">
<!-- 頭像 -->
<view class="avatar">
</view>
<!-- 文字內(nèi)容 -->
<view class="content left">
{{item.botContent}}
</view>
</view>
</view>
</view>
</scroll-view>
<!-- 底部消息發(fā)送欄 -->
<!-- 用來(lái)占位,防止聊天消息被發(fā)送框遮擋 -->
<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">發(fā)送</button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
//滾動(dòng)距離
scrollTop: 0,
userId:'',
//發(fā)送的消息
chatMsg:"",
msgList:[
{
botContent: "hello,請(qǐng)問(wèn)我有什么可以幫助你的嗎?",
recordId: 0,
titleId: 0,
userContent: "",
userId: 0
},
{
botContent: "",
recordId: 0,
titleId: 0,
userContent: "你好呀我想問(wèn)你一件事",
userId: 0
},
]
}
},
computed: {
windowHeight() {
return this.rpxTopx(uni.getSystemInfoSync().windowHeight)
}
},
methods: {
// px轉(zhuǎn)換成rpx
rpxTopx(px){
let deviceWidth = wx.getSystemInfoSync().windowWidth
let rpx = ( 750 / deviceWidth ) * Number(px)
return Math.floor(rpx)
},
//滾動(dòng)至聊天底部
scrollToBottom(){
//外層加一個(gè)延時(shí)函數(shù)是為了能獲取到節(jié)點(diǎn)的準(zhǔn)確信息
setTimeout(()=>{
let query = uni.createSelectorQuery().in(this);
//獲取節(jié)點(diǎn)信息
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)
},
// 發(fā)送消息
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('不能發(fā)送空白消息')
}
},
}
}
</script>
到了這里,關(guān)于【uni-app】uni-app實(shí)現(xiàn)聊天頁(yè)面功能——功能篇(上)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!