uniapp开发聊天APP踩坑记录
Posted ㄏ、Forgetˊ
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uniapp开发聊天APP踩坑记录相关的知识,希望对你有一定的参考价值。
最近工作重心转移到了uniapp上,有一说一,这个框架跨端确实牛逼,一套代码能一次编译到多端使用。但随之而来的兼容性问题也是层出不穷,同样的在面临APP底层的改动也显得力不从心。同时,uniapp的性能问题也是一直被人所诟病的一点,这个点上一还是要提高自己本身的编码能力,二还是得依靠dcloud团队能持续优化框架。
本篇博客是记录使用uniapp开发一个聊天APP的踩坑问题。
一、输入框吞字,光标闪动问题
uniapp中使用输入框,无论是input
组件还是textarea
组件,都存在一个问题。就是如果组件绑定v-model
的话,输入的时候在苹果手机或者部分特殊的有待选区域的输入法,会存在输入框吞字,从文字中间输入时光标会闪动到最后的两个BUG。
该问题的解决方案,最终只能使用:value
去绑定输入框,为输入框分配两个变量,一个真实的value
值,一个是临时的tempValue
值。临时tempValue
值用于在输入触发的@input
事件内实时接收,真实的value
值只在第一次由无值到有值的时候接收一次,而后只需在发送的时候设置真实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 = '' // 清空输入框
}
}
二、组件key值问题
博主封装了一个消息气泡渲染组件,只需要将必要的参数传递进去即可渲染各种消息,但是在开发过程中,发现了气泡消息抛出来长按事件所带的参数错乱的问题,后经研究为组件加上了key
值才解决。
<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>
可能是vue中对组件的更新机制不同,所以v-for
循环中的组件也需要给key
值。
三、消息定位问题
项目中的聊天页,使用的是scroll-view
配合封装好了的富文本组件来渲染各种消息,由于下拉加载更多消息时总会有屏幕闪动的现象出现,故最后是两层scroll-view
来配合使用,一层是真消息,一层是假消息。加载更多时,假消息显示真消息隐藏,等到消息完全渲染定位完毕后再隐藏假消息、显示真消息。
(1)滚不到最底部的问题
在开发的过程中,常常遇到发送消息时,滚不到最底部;亦或者进入聊天页时,滚不到最底部的情况。
针对此,一开始是不断地瞄点滚动到底部,一进入页面就会触发七八次goBottom
函数。
后经过优化,整理了思路,改成了判断消息是否完全渲染完毕后,再执行goBottom
函数。而判断消息是否完全渲染完毕,则需要用到uni.createSelectorQuery()
这个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)下拉加载更多消息瞄点定位不准的问题
同样的,下拉加载更多消息也是存在有瞄点不准确的问题,而一开始的解决方案,是简单粗暴的延时两秒钟,这直接导致了用户等待的时间过长的问题出现,且还不一定能准确的定位到。
参照了滚动到底部的做法,博主举一反三,也通过判断消息是否完全渲染完毕来决定瞄点的时机,以确保瞄点定位准确。
// 加载更多
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 ()
})
}
总结
其实呢,网上一直存在有声音在诟病uniapp,但是讲句道理,能够以一套代码运行到多端的技术还是挺牛逼的,尽管目前来说这项技术还不是很成熟(性能问题、兼容问题)。
uniapp能带领我们的项目走向多远,其实还是可以期待的,当然不能光指望dcloud团队,个人代码的写法也很关键,继续努力吧…
以上是关于uniapp开发聊天APP踩坑记录的主要内容,如果未能解决你的问题,请参考以下文章