vue 特殊路由设计

在 vue-router 的使用中,有时会面临这样一个问题,那就是 vue-router 的设计要求 component层级和 route 层级保持一致。

const route = {
  path: '/list',
  name: 'list',
  component: List,
  children: [{
    path: 'detail/:id',
    name: 'detail',
    component: Detial,
  }]
}

上面的这种常见的路由系统,当访问detail二级路由时,List 和 Detail 组件会同时渲染至页面中。

但是有些时候我们不需要List 和 Detail同事渲染,只需要渲染一个。

这个问题初看很简单,如果只是为了达到 List 和 Detail 同时只有一个存在,只需将路由重新设计为扁平化的即可。然而这会破坏这两个路由本身所拥有的父子语义,因为 UI 的表现而去破坏语义是不理想的。其次,我们项目中还有一个根据路由层级自动生成的面包屑导航,破坏 list 和 detail 的父子关系会导致面包屑导航无法正确工作。

    +---------------------+
    |   当前最深匹配的路由   | 
    |       是否与         | 
    |    自身路由匹配       |
    +---------------------+
               |
         yes   |     no
      +--------+--------*
      |                 |
      v                 v  
  +------+        +------------+
  | show |        |    show    |
  | self |        | child route|
  +------+        +------------+    

$route.matched 存放着当前所有匹配的路由, 中的最后一个项就是当前匹配层次最深的路由。我们可以通过路有对象的 instances.default 取得与此路由相关联的 component 实例,然后与当前组件实例比较一下即可。最后我们通过手写 vue 的 render 方法来完成条件渲染。

最终,我们采取了高阶组件的实现方式,为组件提供子路由匹配时,将自己”隐藏“的功能。

代码实现

export default function routeReplaceSelf(component) {
  return {
    name: 'routerReplaceSelf',
    computed: {
      showChild() {
        const deepestMatchedRoute = this.$route.matched[this.$route.matched.length - 1];
        return deepestMatchedRoute.instances.default !== this;
      },
    },
    render(h) {
      return this.showChild ? h('router-view') : h(component);
    },
  };
}

使用方法

routes: [
    {
      path: '/',
      redirect: '/list'
    },
    {
      path: '/list',
      name: 'List',
      component: routeReplaceSelf(List),
      children: [
        {
          path: 'detail/:id',
          name: 'Detail',
          props: true,
          component: Detail
        }
      ]
    }
  ]

还有一个小问题,当从子路由返回父组件时,父组件会重新 mount。这里可以借助 keep-alive 来缓存组件避免不必要的 mount

render(h) {
  const child = this.showChild ? h('router-view') : h(component);
  return h('keep-alive', [child]);
},
发布了117 篇原创文章 · 获赞 446 · 访问量 62万+

猜你喜欢

转载自blog.csdn.net/zhuoganliwanjin/article/details/95451364