uniapp development chat APP stepping pit record

Recently, the focus of work has shifted to uniapp. One thing to say, this framework is really awesome across terminals. A set of code can be compiled and used on multiple terminals at one time. However, the ensuing compatibility issues are also emerging one after another, and the same changes in the bottom layer of the APP are also powerless. At the same time, the performance problem of uniapp has always been criticized by people. On this point, we still need to improve our own coding ability, and second, we still have to rely on the dcloud team to continuously optimize the framework.
This blog is to record the stepping problem of using uniapp to develop a chat APP.

1. The input box swallows characters and the cursor flickers

There is a problem with using the input box in uniapp, whether it is inputa component or a component. textareaThat is, if the component is bound v-model, when inputting on an Apple mobile phone or some special input methods that have areas to be selected, there will be a bug that the input box swallows characters, and the cursor will flicker to the last two BUGs when inputting from the middle of the text.
The solution to this problem can only be used :valueto bind the input box and assign two variables to the input box, one real valuevalue and one temporary tempValuevalue. The temporary tempValuevalue is used to receive in real time in the event triggered by the input @input. The real value is only received once when it changes from no value to value for the first time, and then you only need to set the real value to empty valuewhen sending to clear the input box.value

<template>
	<textarea :value="value" @input="handleInput"></textarea>
	<button @click="handleClickSend">发送</button>
</template>

export default {
    
    
	data: {
    
    
		value: '',
		tempValue: ''
	}
	handleInput(event) {
    
    
		const value = event.detail.value
		if(!this.value) {
    
    
			// 第一次值为空时赋给真实值
			this.value = value
		}
		this.tempValue = value // 临时值用于实时接收
	}
	async handleClickSend() {
    
    
		if(!this.value) {
    
    
			return
		}
		// 发送时,临时值存储的为当前输入框内的值
		// 随后将真实value值设置为空实现清空输入框
		// 模拟发送请求
		const res = await this.$axios.post({
    
    
			url: xxxx,
			text: this.tempValue 
		})
		this.value = '' // 清空输入框
	}
}

2. Component key value problem

The blogger encapsulated a message bubble rendering component, which can render various messages only by passing in the necessary parameters. However, during the development process, it was found that the parameters of the long press event thrown by the bubble message were out of order. Research adds keyvalue to components to resolve.

<template>
	<view class="chat-warp" v-for="item of msgList" :key="item.id">
		<!-- 注意,需要给组件也给key值 -->
		<chat-item :item="item" :key="item.id"></chat-item>
	</view>
</template>

It may be that the update mechanism for components in vue is different, so v-forthe components in the loop also need to give keyvalues.

3. Message positioning problem

The chat page in the project uses packaged scroll-viewrich text components to render various messages. Since there will always be screen flickering when more messages are loaded from the pull down, so the last two layers are scroll-viewused together. One One layer is true news and one layer is fake news. When loading more, the false message will be displayed and the real message will be hidden. After the message is completely rendered and positioned, the false message will be hidden and the real message will be displayed.

(1) The problem of not being able to scroll to the bottom

During the development process, it is often encountered that when sending a message, the scroll cannot reach the bottom; or when entering the chat page, the scroll cannot reach the bottom.
In response to this, at the beginning, it was constantly aiming and scrolling to the bottom, and goBottomthe function will be triggered seven or eight times as soon as it enters the page.
After optimization, the idea was sorted out, and it was changed to judge whether the message is completely rendered before executing goBottomthe function. To judge whether the message is completely rendered, you need to use uni.createSelectorQuery()this API.

// 在onReady钩子中调用goBottom
onReady() {
    
    
	this.$nextTick(() => {
    
    
		this.goBottom()
	})
}
// 滚动到底部函数
goBottom() {
    
    
	this.scrollView = '' // scrollview瞄点置空
	this.$nextTick(async () => {
    
    
		const res = await this.checkMsgIsRender('btm') // 检测最底部的消息是否完全渲染完毕
		if(res) {
    
    
			this.scrollView = 'bottom' // 瞄点至底部
		} else {
    
    
			this.goBottom()
		}
	})
}
// 检测消息是否渲染完毕
checkMsgIsRender(position) {
    
    
	let msgID = ''
	if(position === 'btm') {
    
    
		// 底部
		// 找到最底部的消息ID
		msgID = xxxx
	} else {
    
    
		// 顶部
		// 找到最顶部的消息ID
		msgID = yyyy
	}
	// 返回一个Promise
	return new Promise((resolve) => {
    
    
		const query = uni.createSelectorQuery().in(this)
		query.select('#id').boundingClientRect(data => {
    
    
			// 存在data,且存在宽和高,视为渲染完毕
			if(data && data.width && data.height) {
    
    
				resolve(true)
			} else {
    
    
				resolve(false)
			}
		}).exec();
	})
}

(2) Pull down to load more information The problem of inaccurate aiming point positioning

Similarly, there is also the problem of inaccurate aiming points when pulling down to load more messages, and the initial solution is a simple and rude delay of two seconds, which directly leads to the problem of users waiting too long, and Not necessarily accurate positioning.
Referring to the practice of scrolling to the bottom, the blogger draws inferences from one instance, and also decides the timing of the aiming point by judging whether the message is completely rendered, so as to ensure the accurate positioning of the aiming point.

// 加载更多
async loadMore() {
    
    
	await this.getMoreMsg() // 向服务器获取更多消息或者展示本地消息,该函数不展开
	let location = async () => {
    
    
		const res = await this.checkMsgIsRender('top') // 检测最顶部的消息是否完全渲染完毕
		if(res) {
    
    
			// 这里还需要找到需要瞄点过去的消息ID,zzzz
			this.scrollView = zzzz // 瞄点到消息zzzz
		} else {
    
    
			location ()
		}
	}
	this.scrollView = '' // scrollview瞄点置空
	this.$nextTick(() => {
    
    
		location ()
	})
}

Summarize

In fact, there have always been voices criticizing uniapp on the Internet, but to be honest, the technology that can run to multiple terminals with one set of code is quite awesome, although this technology is not very mature at present (performance issues, compatibility issues ).
How far uniapp can lead our project, we can actually expect it. Of course, we can’t just rely on the dcloud team. Personal code writing is also very important. Keep working hard...

Guess you like

Origin blog.csdn.net/weixin_43905402/article/details/116377419