[uni-app] uni-app implements chat page function——function article (Part 1)

Article directory

foreword

The previous article talked about how to layout, this article will talk about how to use uni-app to realize the most important function of the chat page of the mini program - after sending a message, the page scrolls to the bottom (refer to many articles and finally find a more suitable method ).

For other functions (refer to WeChat), later articles will describe the specific implementation methods

  • When the chat box is clicked, the chat box is lifted with the keyboard and the chat message list scrolls to the bottom, but the overall page does not lift
  • The chat box textarea adapts to the height according to the content, and the chat message list scrolls to the bottom as the chat box increases (to put it bluntly, the bottom message will not be blocked by the increased chat box)

train of thought

Since we use chat scrolling on the layout scroll-view, a container for storing message lists is nested inside (as shown in the left figure), an important attribute in scroll-view is that the scroll-topofficial document explains the setting of the vertical scroll bar position .

When the length of the message list exceeds the height of the scroll-view, the height difference between them is the scrolling distance of the scroll-view (as shown on the right).

Please add a picture description

Use this function to obtain node information boundingClientRect. For specific methods, please refer to the official website uni.createSelectorQuery() | uni-app official website (dcloud.net.cn)

pit

The code of the original js part is written like this:

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
		}
	})
},

However, during the actual measurement (small program simulator and real machine), it is found that the scrolling position sometimes does not reach the bottom (as shown in the figure, in fact, there is a message below that is covered and not displayed), and sometimes it can be scrolled to the very bottom.

Please add a picture description

I initially suspected that the acquisition of node information was inaccurate, so I searched for boundingClientRect()relevant information about this function. There was no explanation for this problem in the official document, and I found a solution later.

Reference article: Wechat applet boundingClientRect obtains inaccurate element node location information_LGDmar's Blog-CSDN Blog

The problem : the page is not rendered and the node information is obtained

Solution :

Method 1: You can set a delay function setTimeout, because we don't know the rendering time, so I got a delay time that meets the requirements through experiments.

// 滚动至聊天底部
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)
},

Method Two:

Use $nextTickmeans to execute a callback function after the next DOM update.

//滚动至聊天底部
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)
			})
		}
	})
},

Code

Vue page:
(If you need to refer to the css part, please see the layout of my previous article)

<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>

Guess you like

Origin blog.csdn.net/qq_51250105/article/details/130145862