使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 可以自定义路由切换时页面如何滚动。
注意:这个功能只在支持 history.pushState的浏览器中可用
1. 先给占位符加一层缓存
Home 是需要记住滚动条位置的组件
<keep-alive include="Home">
<router-view></router-view>
</keep-alive>
2. 在路由上加一个源信息meta,记录滚动条的top值
const routes = [
{
path: '/home',
component: Home,
meta: {
isRecord: true,
top: 0
}
}
]
3. 使用 scrollBehavior
? 在文档页面(http://localhost:8080/document)拉动滚动条,然后刷新浏览器会发现滚动条依然在原来的位置,这是浏览器的默认行为,会记录浏览器滚动条默认位置。
? 但是点击浏览器“前进/后退”按钮,会发现当初那个页面的滚动条从0开始了,没有记录上一次滚动条的位置。现在要求点击浏览器“前进/后退”按钮,页面滚动条要记录上一次的位置,这时需要设置它的的滚动行为。
? 这时候需要在路由配置中设置 scrollBehavior(to,from,savePosition)函数,函数有三个参数。scrollBehavior() 函数在点击浏览器的“前进/后退”,或者切换导航的时候触发。
- to:要进入的目标路由对象,到哪里去
- from:离开的路由对象,哪里来
- savePosition:会记录滚动条的坐标,点击前进/后退的时候记录值{x:?,y:?}
const router = new VueRouter({
routes: [...],
scrollBehavior (to, from, savedPosition) {
}
})
第三个参数 savedPosition 当且仅当 popstate 导航 (通过浏览器的 前进/后退 按钮触发) 时才可用。 在该方法内,可以通过判断路由to,from两个对象来做一些必要的判断; savedPosition 参数是记录的上次滚动的位置; 通过return {x:number,y:number}来控制页面滚动的位置;
scrollBehavior (to, from, savedPosition) {
return{x:0, y:0}
}
- 想要在后退时,滚动到上次滚动的位置,如果满足条件,savedPosition有值的情况下:
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { x: 0, y: 0 }
}
}
当页面数据需要请求加载有延迟的情况下,页面如果直接滚动,会出现滚动后,页面数据请求回来,DOM重新渲染,滚动失效的情况;
必须使用异步滚动,利用setTimeout跳出主线程将回调事件放到队列中。由于mouted比scrollBehavior函数早执行,所以异步请求的回调事件优先进入队列,接下去才是setTimeout的回调事件。根据队列 先进先出的原理。先执行了异步请求回调事件对data中的变量a做赋值操作。此时相当于这已经是个静态页面了,接着我只要执行return { x:0, y: 100 }。这样就已经触发了页面滚动到100px的效果。但是由于data数据发生改变,页面重新渲染又回到顶部。这时整个轻触滚动效果已经暗中执行完成,不会再出现遮罩层了。
官方文档给补充了异步滚动的方法:
scrollBehavior (to, from, savedPosition) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ x: 0, y: 0 })
}, 500)
})
}
这个会在返回后,有一定延迟再滚动,可以根据自己项目的具体情况进行一定修改,兼容;
-
最终结果
const router = new VueRouter({
routes,
scrollBehavior(to, from, savedPosition) {
console.log(to.meta.top)
return new Promise((resolve, reject) => {
setTimeout(() => {
if (savedPosition) {
resolve(savedPosition)
} else {
resolve({ x: 0, y: to.meta.top || 0 })
}
}, 100)
})
}
})
4. 给页面添加事件监听
Home.vue
activated() {
fn = this.recordTopHandler()
window.addEventListener('scroll', fn)
},
deactivated() {
window.removeEventListener('scroll', fn)
}
fn 函数 用来记录滚动条的位置
- 使用了一个防抖函数
_.debounce(func, [wait=0], [options=]) ,官方文档:lodash.debounce - _.debounce方法的作用是防抖动,当你的事件在不断触发的时候,会根据你设置的间隔时间只触发一次回调。也就是说当调用动作n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间。(空闲时间大于,设定的时间是才会执行!!!)
recordTopHandler() {
return _.debounce(
() => {
this.$route.meta.top = window.scrollY
},
50,
{ trailing: true }
)
}
|