vue-router扩展实践

我们希望使用vue-router去做什么?

在最近的项目中,我们基于vue全家桶建立一个H5 WAP版项目,我们对该项目有几点设想:

  1. 能够直接嵌入多个APP,作为Hybrid APP;
  2. 简单化的跳转;
  3. 运营配置通用化。

Hybrid

虽然这是一个H5 WAP项目,但部分页面会嵌入到APP里面,同一个页面H_0的点击按钮跳转需要同时兼容两种情况: WAP: H_0 --> H_1 页面H_0点击按钮跳转到页面H_1 Hybird: H_0 --> A_1 页面H_0点击按钮跳转到APP的A_1模块

简单化的跳转

简单化,即没有额外的学习成本就能够使用。目前使用MVVM框架搭建的项目,几乎都会使用路由库Router来完成管理页面的切换,Vue同样也拥有官方Vue-Router的支持,所以,我们希望能够保持和Vue-Router的导航API(push、replace、go)一致的调用方式。

运营配置通用化

项目中的模块跳转是通过管理后台配置,例如首页的九宫格菜单,运营人员会配置不同模块的组合和跳转地址,在APP里面,这个跳转地址是基于schema规则,但在wap端会是基于url或route name来实现,映射关系类似下表:

APP WAP URL WAP Route Name
myschema://category?id=1 /h5/page0/category_fun/1 category_fun

在这个情况下,我们希望运营人员在知晓schema规则的情况下就能够完成H5端的配置,所以我们需要能够兼容schema方式的跳转。

如何选择?

开发一套全新的Router库替换Vue-Router

这个方案从一开始就被排除了,Vue-Router本身已经能够覆盖到我们页面跳转需求,而且也得到开源社区的支持,重新开发一套的成本和效果还是值得好好考虑。

基于Vue-Router进行封装

保持和Vue-Router相同的API,针对不同的环境和地址执行不同的流程。

Router Pre Parse 解析跳转的参数、Url地址、Schema地址以及环境的解析(是否内嵌APP),确定页面应该执行Extent-Router或Vue-Router Extent-Router 实现Schema方式的跳转 这个方式是代码耦合度最低的,结构清晰,而且也方便在未来直接替换Vue-Router,但开发成本也不低,Router Pre Parse需要实现类Vue-Router的导航API以及监听popstate事件以接管Vue-Router的默认行为,完整解析Vue-Router的规则,简单来说,就是实现Vue-Router大部分的解析行为,将Vue-Router弱化成单纯的跳转组件。

基于Vue-Router的beforeEach事件扩展

基于开发成本的考虑,我们最后采用了这个最简单的方案。

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

当一个导航触发时,beforeEach全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。 前置触发、等待执行、允许中断,这是beforeEach提供的三个优势,而本身是Vue-Router的函数又提供给我们解析跳转参数、Url的基本功能。我们也能够基于Vue-Router的导航API直接方便的调用。

实现这样一套机制,我们能够实现多种跳转格式的兼容:

this.$router.push({
    name: category_fun,
    params: {
            id: 1
    }
});
this.$router.push({
    name: 'myschema://category?id=1'
});
this.$router.push({
    name: '/h5/page0/category_fun/1'
});

甚至,在Route Schema映射模块里,也实现了弹窗这样的无跳转schema,反正next(false)能够中断导航。

this.$router.push({
    name: 'myschema://justopendialog?data={title:"标题",text:"这是一个弹窗而已"}'
});

总结

这个需求场景具有其特殊性,我们才需要做这种扩展尝试,目标已经实现,但是否可靠仍需要在未来继续踩坑,这里仅仅是提供一个思路,也许不断地迭代会让我们从beforeEach的方案逐步过度到第二方案甚至重写一个路由轮子。

本文来自网易实践者社区,经作者李瑞禧授权发布。