在普通页面中,点击浏览器的返回按钮,在返回到上一页时会处在上次浏览的位置。单页面应用中,由于始终是同一个页面, 因此需要自行实现页面返回时的锚点。Vue-router的Scroll Behavior可以用于解决这个问题,但是只能应用在HTML5 history模式。本文实现了在hash模式下的锚点跳转。

锚点位置存储

Vue-router要求在HTML5 history模式下,是为了使用pushState、replaceState API以及popstate事件:

1

2

3

4

5

6

7

8

9// Vue-router中的push方法

push (location: RawLocation, onComplete?: Function, onAbort?: Function) {

const { current: fromRoute } = this

this.transitionTo(location, route => {

pushState(cleanPath(this.base + route.fullPath))// 存储页面锚点位置

handleScroll(this.router, route, fromRoute, false)

onComplete && onComplete(route)

}, onAbort)

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17// pushState方法

export function pushState (url?: string, replace?: boolean){

saveScrollPosition()

// try...catch the pushState call to get around Safari

// DOM Exception 18 where it limits to 100 pushState calls

const history = window.history

try {

if (replace) {

history.replaceState({ key: _key }, '', url)

} else {

_key = genKey()

history.pushState({ key: _key }, '', url)

}

} catch (e) {

window.location[replace ? 'replace' : 'assign'](url)

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16export function setupScroll (){

window.addEventListener('popstate', e => {

saveScrollPosition();

if (e.state && e.state.key) {

setStateKey(e.state.key);

}

})

}

window.addEventListener('popstate', e => {

this.transitionTo(getLocation(this.base), route => {

if (expectScroll) {

handleScroll(router, route, this.current, true)

}

})

})

在hash模式下需要我们自己记录锚点位置。可以维护一个与history相同的数组,每次页面跳转时在Vue-router提供的钩子函数中遍历数组,存储锚点位置。

锚点滚动

Vue-router本身提供了scrollBehavior方法,用来进行锚点跳转。但是该方法只能用在HTML5 history模式下。研究了一下其源码:vue-router/src/util/scroll.js,发现也是使用window.scrollTo()来进行页面的滚动。重要的是设置滚动的时机,应当在下一个页面绘制完成后进行跳转(wait until re-render finishes before scrolling)。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24// wait until re-render finishes before scrolling

router.app.$nextTick(() => {

let position = getScrollPosition();

const shouldScroll = behavior(to, from, isPop ? position : null);

if (!shouldScroll) {

return;

}

const isObject = typeof shouldScroll === 'object';

if (isObject && typeof shouldScroll.selector === 'string') {

const el = document.querySelector(shouldScroll.selector);

if (el) {

position = getElementPosition(el);

} else if (isValidPosition(shouldScroll)) {

position = normalizePosition(shouldScroll);

}

}

else if (isObject && isValidPosition(shouldScroll)) {

position = normalizePosition(shouldScroll);

}

if (position) {

window.scrollTo(position.x, position.y);

}

})

我们目前已经自行记录了锚点,因此可以在router中模仿一个跳转过程:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16router.beforeEach((to, from, next) => {

next();

// 重要的是设置跳转的时机。过早的话页面还没加载完成,高度不够导致不能滚动。过晚的话会造成页面的闪烁。

router.app.$nextTick(() => {

// 获取history数组中的最后一个browserHistoryLast

if (to.fullPath === browserHistoryLast.path

&& browserHistoryLast.pos) {

document.body.scrollTop = browserHistoryLast.pos;

}

else {

document.body.scrollTop = 0;

}

});

});

在router的钩子函数中,调用next之后,在$nextTick中进行页面的滚动,即可达到和scrollBehavior相似的效果。

需要注意的是,各个页面的数据应当存储在vuex中,不能每次进入页面都发送请求(即使不锚点也应当这么做)。否侧因为返回时页面还在请求数据,不能达到锚点的效果。

关于过场动画

如果页面跳转有过场动画存在,非常容易在锚点滚动时发生闪烁。尝试了几种方式,都没能达到很好效果。

尝试过的方法的思路在这里记录一下,这些方法都会有很大的抖动闪烁,根本原因还是页面跳转的时机不对:

返回到有存储pos的旧页面时,在onTransitionAfterEnter中将页面滚动到记录的位置。打开新页面时,在onTransitionBeforeStart中将页面滚动设置为0,确保新页面在顶部。

vue-router的过渡动画使用的是absolute定位+transform。因此尝试了给页面设置top值来消除闪烁。在跳转前给当前页面设置与目标页面滚动位置相同的top值,在滚动结束后由于不再是absolute定位,top值不再生效,没有闪烁发生。在返回时,列表页会首先绝对定位到首页要滚动的位置(此时会有闪烁),之后直接跳转到首页。闪烁集中在返回过渡效果之前。

其他问题全局mixin中不能写组件中的过渡钩子,如beforeRouteEnter等,会报错。

computed只有在vuex中的变量变化时,才会进行更新。import进来的值不行。

在onTransitionBeforeStart修改变量,不会使from页面中的computed更新。如果想要在页面跳转时更新from页面的computed,需要在router的钩子函数中进行修改,在this.$nextTick中调用next()。

router锚点和html锚点,hash模式下Vue-router页面返回锚点(scroll behavior)实现相关推荐

  1. Vue 移动端 hash模式下微信授权登录

    需求分析: 1.移动端微信公众号项目,需要获取微信授权进行登录 2.默认打开首页,在路由进入之前进行判断,有如下三种情况 3.本项目有两种账号类型:商家.企业,需在登录页进行选择 未授权过,跳到微信授 ...

  2. 解决vue路由hash模式下,微信网页授权问题

    解决vue路由hash模式下,微信网页授权问题 本人开发负责微信公众号端,菜单都是自定义菜单,然后每个菜单路径都是经过授权如:http://xxxx.com/ceshi/wechat/authoriz ...

  3. 微信分享的链接,手机打开白屏,单页面应用(Hash模式下),实现微信分享

    前言:现在将相关的产品分享至朋友圈,进行宣传,成为一种很常见的方式.本文,主要想分享一下,微信分享所遇到的坑,微信分享的链接,手机打开白屏,以及产生的原因. 前端微信分享的基本步骤: 一.绑定域名 先 ...

  4. vue hash模式下微信授权登录

    背景 vue-cli项目.路由是hash模式.需要授权的场景有:项目入口处(App.vue),指定页面(创建时.methods 方法内):可以携带参数 思路 由于hash模式# 号的存在,授权后链接会 ...

  5. vue/react的hash模式下的锚点效果

    就是如链接所示:http://oa-img.oss-cn-qingdao.aliyuncs.com/up-img/pic-60044/xknTNnFHsxFaEJYJ3P5ZD82jnfXWTjHj. ...

  6. VueRouter — vue路由hash模式和history模式

    目录 一.前言 二.hash模式 三.history模式 一.前言 对于hash模式和history模式,最直接的区别就是地址栏带不带"#"号了. vue脚手架搭建的项目的路由默认 ...

  7. Vue router 模式 hash 和 history

    目录 Vue router 基本使用 Vue-router 传参 hash 模式 Vue-router hash history 模式 Vue router 基本使用 用 Vue + Vue Rout ...

  8. vue router 的两种路由模式hash与history的区别

    文章目录 两种模式 特点 总结 两种模式 前端路由的核心,就在于 -- 改变视图的同时不会向后端发出请求. hash模式是通过改变锚点(#)来更新页面URL,并不会触发页面重新加载,我们可以通过win ...

  9. Use history mode for router? Vue-router 中hash模式和history模式的区别

    再通过vue-cli创建项目的时候,会出现 Use history mode for router? 也就是再问你:是不是用history模式来创建路由 hash模式和history模式的不同 最直观 ...

最新文章

  1. 三星s10android10功能,三星S10系列现场上手体验:“安卓机皇”真的名副其实
  2. nginx安装(正式)
  3. python爬取豆瓣电影并分析_爬取豆瓣电影top250提取电影分类进行数据分析
  4. 给数据表中的字段添加约束
  5. js php调用webservice,php调用web services两种方法soap和curl
  6. PowerPivot for Sharepoint 2010 配制及常见错误
  7. 女友晚安之后依然在线:python男友用20行代码写了个小工具
  8. Adblock Plus无法屏蔽CSDN右下角广告解决
  9. C#基础之--线程、任务和同步:一、异步委托
  10. 【转】MySQL日期时间函数大全
  11. 关于高德地图坐标批量手动拾取的简易办法
  12. [转]拍照怎么搜题?(下)
  13. 如何规避适配风险?以《乱世王者》为例,探秘手游兼容性测试之路
  14. ObiFruid创建流体,ObiFruid学习笔记
  15. HackTheBox::Doctor
  16. 实用算法 002: SAM 上的根号暴力
  17. SQL日期、转换、通用函数
  18. 【VB编程】05.MsgBox与InputBox函数
  19. 在Simulink中利用simmechanics对三自由度的串联机械臂进行仿真
  20. 92.最后的综合案例

热门文章

  1. Android---什么是3G
  2. 借口很多呀嘛接口也很多呀嘛态也很多
  3. 【转】Android加密算法:AES、Base64加密算法
  4. What means the error-message 'java.lang.OutOfMemoryError: GC overhead limit exceeded' in Java?
  5. c语言标准库 swap,swap
  6. npm i依赖版本兼容问题处理
  7. InstallShield LaunchAppAndWait运行另一个程序并等待该程序终止。
  8. Java抓取淘宝/天猫商品详情
  9. 服务器无法通过系统非页面共享区进行分配,服务器无法通过系统非页面共享区来进行分配的解决方法...
  10. 鸿蒙思维和小央美,中心路汝南路站附近艺术培训