1. 应用场景——聊天
在聊天的时候,展示聊天内容的元素是可以滚动的,通过上下滚动来查看过往消息。不过在首次打开聊天页面以及发送新消息时需要固定在滚动的最底部以及时展示最新的消息,这样才能获得比较好的用户体验。
效果:
2. 实现
假设滚动的元素为div
,只需要设置下面这个语句即可:
div.scrollTop = div.scrollHeight;
scrollHeight
属性:
只读属性,是一个元素内容高度的度量,包括由于溢出导致的视图中不可见内容。
scrollTop
属性
对于设置了垂直滚动的元素,scrollTop
的值是这个元素的内容窗口顶部到它的可视窗口顶部的距离。这是个差值,意味着向上滚动的高度。
这里要区分两个概念:内容窗口和可视窗口。
内容窗口:
内容窗口就是实际内容所占的box,高度随着内容的高度增大而增大(默认向下增大),超出div
的部分需要滑动才可见。
可视窗口:
就是设置了滚动属性的元素,它的宽高有多少可视的范围就是多大。
因此我们当内容窗口的高度变大时,比如发送了新消息,我们将scrollTop
的值设成这两个窗口高度的差值就实现了自动固定到底部的效果。
srcollHeight
就是内容窗口的高度,我们还需要获得可视窗口的高度。其实我们不需要获得,因为可以利用scrollTop
的一个特点:如果设置了超出这个容器可滚动的值,scrollTop 会被设为最大值(也就是滑动到最底部)。
因此我们可以设置成一个比较大的值赋给它,这个值就可以选择srcollHeight
,这个值会始终会超出容器的可滚动范围(因为它的高度就是可滚动范围+视窗高度),因此就实现了固定到底部的效果。
3. 巧用 nextTick
虽然使用
div.scrollTop = div.scrollHeight;
这个语句就能达成效果,但在实际使用时会有bug,比如在这个聊天场景中,刚发送新消息时,没有自动滑动到最后一条消息,而是滚动到倒数第二条消息了。
这是因此组件在刷新时有延迟,我们没有读取到选然后的最新值导致的。
解决办法就是使用nextTick函数封装一下。
nextTick(() => {div.scrollTop = div.scrollHeight;})
nextTick
的作用
nextTick
是vue 提供的一个API,作用是下一次DOM更新后调用的方法。
原理:
当更改了vue的响应式状态之后,DOM的刷新不是同步的,而是将刷新dom的任务放到一个队列中去等待执行,直到下一个tick
才一起执行。nextTick
就是监听dom刷新的方法,在tick
了之后会立即被执行,因此可以利用这个原理解决之前的bug。
详见: vue: nextTick