场景描述
近日碰到了一个项目需求,使我不得不去研究vue-router里路由切换的具体过程,在这个过程中发生了什么事情。
场景大概如下:在一个表单页面里,用户可以选择提交,也可以选择不提交而离开。产品经理要求数据不保存在本地浏览器里,在用户提交成功后销毁表单数据;或者用户离开页面(点击取消或者其他tab)时,出现弹窗,提醒用户表单数据还未提交,是否放弃。
在这个场景里,难点在于:1. 如何监听用户离开页面或者关闭页面的事件; 2.如何在用户选择放弃提交以后还能正确指向之前点击的路由目标。
如上图所示,用户可以点击取消,或者任何侧边dashboard的tab,这就说明,modal弹窗的“取消”按钮上不能增加固定的路由链接,因为无法确定用户会点击哪个路径。只能通过先记录点击路径,然后绑定到取消按钮上。
轮子分析
1.在轮子中解决
首先,内置location对象是可以使用的,但造成的问题是与vue-router分离性太强,同时也无法做到简洁的数据绑定。因此,最佳的方案还是在vue-router本身的功能中解决。
在之前我对于vue-router的了解并不多,一般只是用来做一些基本的路由控制和页面跳转传参,类似如下代码:
|
|
同时会用到一些路由嵌套,参数传递,大多数情况下,这些功能已经足够覆盖很多项目需求了。
2.vue-router钩子函数生命周期
搞懂了vue路由里钩子函数的运转过程,就可以轻松解决各种跳转需求。
路由的切换过程,本质上是执行一系列路由钩子函数,钩子函数总体上分为两大类:
- 全局的钩子函数
- 组件的钩子函数
全局的钩子函数定义在全局的路由对象中,组件的钩子函数则定义在组件的route选项中。
全局钩子函数
全局钩子函数有2个:
- beforeEach:在路由切换开始时调用
- afterEach:在每次路由切换成功进入激活阶段时被调用
组件钩子函数
组件的钩子函数一共6个:
- data:可以设置组件的data
- activate:激活组件
- deactivate:禁用组件
- canActivate:组件是否可以被激活
- canDeactivate:组件是否可以被禁用
- canReuse:组件是否可以被重用
切换对象
每个切换钩子函数都会接受一个 transition 对象作为参数。这个切换对象包含以下函数和方法:
- transition.to
表示将要切换到的路径的路由对象。- transition.from
代表当前路径的路由对象。- transition.next()
调用此函数处理切换过程的下一步。- transition.abort([reason])
调用此函数来终止或者拒绝此次切换。- transition.redirect(path)
取消当前切换并重定向到另一个路由。
具体的分析过程可以查看官方文档,也可以看这位仁兄的详细教学。
附一张详细教学里的生命周期图片:
3.实战解决
首先,对我目前的这一个组件绑定一个新的data:completeSubmit。根据这个data的布尔值来判断是否应该跳出询问的弹窗。
出现弹窗的时候,一定要加transition.abort()这行代码,这样router就不会继续前进,地址栏的url也不会进行变化。
那么,如何记录用户即将前往的页面router呢。我们此时先把transition打印出来看一下具体的内容:
可以看到,transition里就有关于目的地的记录。那么只要在组件的data里绑定一个新的数据就可以进行记录了。
通过this.toPage我们就可以拿到目的地了。
modal组件里,通过$dispatch来传递事件。
然后在本组件里进行事件的接收
在用户确定离开的时候,我们首先把modal隐藏,接着把this.completeSubmit的布尔值进行更改(否则router部分的transition无法进行next()),然后通过this.toPage拿到之前用户的点击地址,在router的对象里进行操作。
关于router的编码式导航,请一定仔细看文档,并区分vue-router的版本号。2.0版本和0.7版本的写法有明显不同。但二者都是支持编码式导航的(另一种方式是常见的html标签式导航)。
最后,清空用户的填写记录,就大功告成啦。