@[toc]
需求: 仿微信聊天
需求很简单, 就是仿微信聊天, 下拉加载历史聊天记录时, 能保持浏览位置, 在网上找了一些例子都不太完美, 要么不能保持浏览位置, 要么会来回跳一下, 反正就是效果不好, 决定还是自己研究研究
处理方法
template 模板部分
使用 uniapp 自带的scroll-view
来做滚动容器, 需要配合以下属性:
scroll-y
: 允许纵向滚动scroll-top
: 设置竖向滚动条位置upper-threshold
: 距顶部/左边多远时(单位px),触发 scrolltoupper 事件@scrolltoupper
: 滚动到顶部/左边,会触发 scrolltoupper 事件scroll-anchoring
: 开启 scroll anchoring 特性,即控制滚动位置不随内容变化而抖动,仅在 iOS 下生效
<scroll-view
class="msg-list"
scroll-y="true"
:scroll-top="scrollTop"
@scrolltoupper="getMessageList"
upper-threshold="0"
:scroll-anchoring="true"
>
<view class="content-box-loading">
<!-- 加载到最后页了 -->
<text v-if="isCompleted">--- 没有更多了 ---</text>
<!-- 加载中 -->
<u-loading v-if="loading" mode="flower"></u-loading>
<!-- 还可以写些其他状态 -->
</view>
<view class="message-list">
<view class="message-item" v-for="(item, index) in messageList" :key="index">{{ item }}</view>
</view>
</scroll-view>
script 部分
详细见代码中的注释
export default {
data() {
return {
loading: false,
isCompleted: false,
// 列表高度
scrollHeight: 0,
// 滚动条位置
scrollTop: 0,
// 消息列表
messageList: [],
page: 1
}
},
computed: {},
onLoad() {
this.getMessageList()
},
methods: {
async getMessageList() {
// 加载中, 或者数据已经加载到最后一页了, 直接 return
if (this.loading || this.isCompleted) {
return
}
// 将loading设置成true, 防止在重复加载
this.loading = true
try {
const data = await this.$api.getMessageList({
// 其他各种入参
count: 15,
page: this.page
})
// 接口返回的数据, 根据实际情况修改
// 聊天记录列表
const messageList = data.data.messageList
// 是否已加载到最后一页
this.isCompleted = data.data.isCompleted
// 合并数据
this.messageList = [...messageList, ...this.messageList]
// 当新数据渲染完成后
this.$nextTick(async () => {
const query = uni.createSelectorQuery().in(this)
query
.select('.message-list')
.boundingClientRect(data => {
// data.height 为已经渲染的聊天列表内容高度
// this.scrollHeight 为上一次聊天列表内容高度, 如果当前为第一次, 那么this.scrollHeight应该为0
// 设置滚动条的高度
this.scrollTop = data.height - this.scrollHeight
// (注意: 如果在模板中, upper-threshold设置的值不为0, 为50, 那么可以加上该值), 如:
// this.scrollTop = data.height - this.scrollHeight + 50
// 将本次列表渲染后的内容高度记录下来, 方便下次加载时使用
this.scrollHeight = data.height
})
.exec()
//如果还有数据
if (!data.data.isCompleted) {
this.page += 1
this.loading = false
}
})
} catch (error) {
console.log(error)
this.loading = false
}
}
}
}
其他
该方法只在H5中用浏览器模拟手机测试通过, 其他平台未测试