务实|滚动条置顶的几种方法
一、前言
在单页应用中,比如vue,常常会遇到跳转到下一页的时候,滚动条保留在上一个页面停留的位置,然而这可能不是我们希望的。此时,用户想要的是每跳转到一个新页面,尤其是详情页跳转到详情页这种场景,滚动条可以重置的顶部。
当然,像详情页返回列表页时,希望返回的时候仍然是原来列表所在位置,这种场景本文不讨论。本文讨论的是每当跳转到一个新页面,要求实现滚动条置顶的场景。
那么,接下来给出几种滚动条置顶的方案,并给出对比分析。
二、实现方案
经验提前说:
建议先试方案一,方案一不好使再试方案二,最后再尝试方案三。这样建议是经验之谈,因为一些人会做一些特殊的路由配置,那可能会使得方案产生意外,比如某些场景下document.body.scrollTop的值在页面跳转前已经是0,显然再设置为0是不会产生滚动条置顶的效果的。而诡异的是跳转前的滚动条并不是置顶的。
遗憾的是未能查清这种诡异的因果,所以建议几个方案都尝试下。实践种,我在两个项目分别用了方案一和方案二,方案反之使用无效果。但对应的方案使用却效果良好,且久经考验未发现bug。
1.方案一
// 在路由前置守卫函数中配置
router.beforeEach((to, from, next) => {
// 滚动条置顶
window.scrollTo(0, 0)
document.body.scrollTop = 0
document.documentElement.scrollTop = 0
// 注意,pageYOffset 直接赋值,在 ie11 会报错,这种报错会导致页面一片空白显示异常
// window.pageYOffset = 0
})
2.方案二:利用 scrollIntoView()
// 在路由前置守卫函数中配置,发生路由变化时(即页面发生跳转时),滚动#app元素到可视区域的顶部,
// 这里是利用#app元素是body元素的特点,因为滚动#app元素到可视区域,且顶部对齐,此时滚动条也会置顶。
router.beforeEach((to, from, next) => {
// 滚动条置顶
// 获取#app根元素
const app = document.getElementById('app')
// behavior: "smooth",设置滚动过程动画过渡效果为smooth
// block: "end",定义垂直方向的对齐方式为 start ,即顶部对齐
// inline: "nearest",定义水平方向的对齐方式为 start
app.scrollIntoView({behavior: "smooth", block: "start", inline: "start"})
})
3.方案三:利用 Element.scrollTop
// 在路由前置守卫函数中配置,设置 #app元素的 scrollTop 的值0,从而达到滚动条置顶的效果
// 需要注意的是,当 app.scrollTop 的值在页面跳转前已经为0的时候,这不会产生滚动条置顶的效果
router.beforeEach((to, from, next) => {
// 滚动条置顶
// 获取#app根元素
const app = document.getElementById('app')
app.scrollTop = 0
})
三、关键技术点小结
1.window.scrollTo(0, 0)
scrollTo() 是 window 的方法,表示将滚动条的位置,滚动到文档中的某个坐标。
其基本用法如下:
// x 是文档中的横轴坐标,y 是文档中的纵坐标。
window.scrollTo( x, y )
window.scrollTo({
left:0, // 等同于x
top: 1000, // 等同于y
behavior: "smooth", // 设置滚动动画效果为smooth,即平滑滚动
})
注意,该函数实际上和 window.scroll是一样的。相对滚动可以参考 window.scrollBy,window.scrollByLines,和 window.scrollByPages。
2.Element.scrollTop = 0
Element.scrollTop 属性可以获取或设置一个元素的内容垂直滚动的像素数。
一个元素的 scrollTop 值是这个元素的内容顶部(卷起来的)到它的视口可见内容(的顶部)的距离的度量。当一个元素的内容没有产生垂直方向的滚动条,那么它的 scrollTop 值为0。
其基本用法如下:
// 设置滚动的距离
Element.scrollTop = intValue; // intValue 是一个整数,表示会将元素滚动到该位置
3.Element.scrollIntoView()
scrollIntoView()方法会滚动元素的父容器,使被调用scrollIntoView()的元素对用户可见。
其基本用法如下:
// 可选,scrollIntoViewOptions:{behavior: "smooth", block: "end", inline: "nearest"}
// 可选,behavior :定义动画过渡效果,"auto"或 "smooth" 之一。默认为 "auto"。
// 可选,block:定义垂直方向的对齐,"start", "center", "end", 或 "nearest"之一。默认为 "start"。
// 可选,inline:定义水平方向的对齐,"start", "center", "end", 或 "nearest"之一。默认为 "nearest"。
Element.scrollIntoView({behavior: "smooth", block: "end", inline: "nearest"});
Element.scrollIntoView({block: "end"});
Element.scrollIntoView();