如果笔记

如果笔记

做有价值的技术笔记

Vue应用滚动条位置管理插件,兼容history模式和hash模式

在Vue应用中,如果我们不对滚动条位置做处理,那么前进或后退时滚动条位置是保持在当前的位置,而不是目标页在前一次被浏览时的位置,这就不符合我们的浏览习惯

浏览非单页应用的页面时,点击浏览器的前进或后退按钮,滚动条位置总能保持在前一次浏览该页的位置,这个体验很自然很好。但在Vue应用(单页应用)中,如果我们不对滚动条位置做处理,那么前进或后退时滚动条位置是保持在当前的位置,而不是目标页在前一次被浏览时的位置,这就不符合我们的浏览习惯。 Vue应用如果是history模式,可以用`vue-router`自带的的`scrollBehavior`实现滚动条位置记忆,但只有在浏览器支持`history.pushState`可用。而且在hash模式下,没有提供自带的方法。 本文要介绍的滚动条位置管理插件,兼容history模式和hash模式,并且代码足够简单。 先贴代码,`lib/scroll-position.js`: ```javascript const doc = document; var cache = {}; export default { // 保存滚动条位置 save(path) { cache[path] = doc.documentElement.scrollTop || doc.body.scrollTop; }, // 重置滚动条位置 get() { const path = this.$route.path; this.$nextTick(function () { doc.documentElement.scrollTop = doc.body.scrollTop = cache[path] || 0; }); }, // 设置滚动条到顶部 goTop() { this.$nextTick(function () { doc.documentElement.scrollTop = doc.body.scrollTop = 0; }); } } ``` 代码就这么几行,是不是很简洁?下面讲怎么使用。 切换路由的时候,首先在`beforeEach`这个钩子里保存离场页面的滚动条位置: ```javascript import ScrollPosition from './lib/scroll-position'; router.beforeEach((to, from, next) => { // 保存滚动条位置 ScrollPosition.save(from.path); next(); }); ``` 然后,在页面的`mounted`钩子上重置滚动条位置: ```javascript mounted() { ScrollPosition.get.call(this); }, ``` 如果mounted钩子不干别的事,那么还可以把代码简化成: ```javascript mounted: ScrollPosition.get, ``` 好了,现在点击浏览器的前进、后退,或者通过js调用`window.history.back()`,页面已经能记住并重置滚动条位置了! 我们的插件里还提供了一个`goTop`方法,因为有些页面不需要记住滚动条位置,并且希望每次进入都是滚动到顶部,这时候就可以用goTop方法了: ```javascript mounted: ScrollPosition.goTop, ``` 那么,为什么要在mounted的时候重置滚动条位置呢?网上有些做法是在路由的beforeEach里使用setTimeout,这样做并不准确,太早了有偏差,太晚了肉眼能看到页面跳动,所以体验不好。而mounted被调用时,当前页面组件已经挂载到DOM树,所以选择在这个钩子重置滚动条。但是,官方文档说了,“mounted不会承诺所有的子组件也都一起被挂载”,所以得用`vm.$nextTick`,这样一来,其实也可以在created这些钩子调用ScrollPosition.get,只不过放在mounted里显得更合时宜。 **需要注意的是**:如果没有缓存接口数据,每次进入都是重新加载数据,那么最好是使用`goTop`而不是记住滚动条位置。 > 大道至简,在编程里对大部分的解决方案都适用,如果你的解决方案太过复杂,那么通常都不是最好的。 【原创内容,谢绝转载】

前端

hahaboy