消息列表向上滚动加载

效果

客服系统的聊天列表,需求是向上滚动加载更多,直到没有消息.先看效果:

监听滚动

在消息容器上添加监听滚动,距离顶部 200px 就触发加载.这里注意要去抖,防止频繁触发导致浏览器卡顿

1
2
3
4
5
6
7
8
9
10
11
this.$refs.chatWrapper.addEventListener("scroll", debounce(this.handleScroll))

handleScroll() {
// 消息数过少不触发
if (this.chatList.length <= 5) return
let scrollPosition = this.$refs.chatWrapper.scrollTop
if (scrollPosition < 200) {
log("滚动距离: " + scrollPosition + ",触发加载更多聊天记录")
this.queryChatToChatList(this.activeContactUUid, 20, this.nextPage)
}
}

加载更多

聊天消息列表是一个数组,所有内容用v-for输出.添加内容只要往数组头部 concat 即可

1
2
3
4
5
6
<div v-for="(chatItem,idx) in chatList "
:class="['msg_item',chatItem.isMeSend?'my_msg':'you_msg']"
:key="idx"
>
<!--聊天项代码-->
</div>

保存原来位置

如果直接把新内容添加到数组头部,我们的滚动距离仍然在消息容器的顶部,这样鼠标稍微移动就会再次触发加载

所以我们要保存原来的位置,在消息记录渲染出来后跳到原来的位置

1
2
3
4
5
6
7
8
9
10
// scrollHeight - scrollTop 为聊天列表需要保留的高度
this.readHeight = this.$refs.chatWrapper.scrollHeight - this.$refs.chatWrapper.scrollTop

// watch 消息数组
// 消息窗口自动滚到底部
this.$nextTick(() => {
// 跳转到上次阅读的高度
this.$refs.chatWrapper.scrollTop = this.$refs.chatWrapper.scrollHeight - this.readHeight
this.readHeight = 0
})

scrollHeight - scrollTop 为聊天列表需要保留的高度,在watch里监听数组变化,等到数组渲染成具体的dom,在$nextTick里把容器滚回原来的位置.由于速度很快用户无法察觉列表已经从顶部闪现回来