实现简单版VueRouter嵌套路由

实现简单版VueRouter嵌套路由

介绍

本文是承接上文《实现简单版VueRouter》的扩大版,在原有基础上加入嵌套路由功能,以用于更深入的学习VueRouter。多有不足之处,请多多交流。

内容拆分

实现VueRouter的嵌套路由功能,主要有两点:

  • 路由匹配时获取代表深度层级的matched数组

    • router-view深度标记

插件测试

修改路由信息以供实现过程中输出信息查看,也便于发现错误问题。

  • 修改 krouter/index.js 中路由信息
// 修改前
{
    path: "/about",
    name: "About",
    component: () => import("../views/About.vue"),
}
// 修改后
{
    path: "/about",
    name: "About",
    component: () =>import("../views/About.vue"),
    children:[
        {
            path: "/about/info",
            component: {
              render(h) {
                return h('div', 'info page')
              },
            }
        }
    ]
  },
  • 修改 about.vue 页面
<!--修改前-->
<div class="about">
    <h1>This is an about page</h1>
    <router-view></router-view>
</div>
<!--修改后-->
<div class="about">
    <h1>This is an about page</h1>
    <router-view></router-view>
</div>

功能实现

matched数组和match方法

matched数组建立

由于是嵌套路由,所以需要在路由变化时找到当前路由相关的路由信息保存起来。而因为嵌套层级的不确定性需要以数组形式进行保存。

该数组的能力囊括了上一篇文中的current的作用,所以在这里将current废弃掉。

// 修改前
const current = window.location.hash.slice(1) || '/';
Vue.util.defineReactive(this, 'current', current)
// 修改后
this.current = window.location.hash.slice(1) || '/';
Vue.util.defineReactive(this, 'matched', []);

match方法

matched数组建立后,需要执行一定操作根据当前地址栏路由路径将匹配的路由信息填充到数组中。

为了便于递归操作,给match方法添加routes参数。

match(routes) {
    routes = routes || this.$options.routes;
    // 递归遍历
    for (const route of routes) {
      if (route.path === '/' && this.current === '/') {
        // 该情况下为首页匹配
        this.matched.push(route);
        return;
      }
      if (route.path != '/' && this.current.indexOf(route.path) != -1) {
        this.matched.push(route);
        if (route.children) {
          this.match(route.children)
        }
        return;
      }
    }
  }

路由深度标记

在router-view组件中进行路由的深度进行标记,再从matched数组中获取到对应的组件信息,通过render函数渲染出来。

  export default {
  render(h) {
    // 标记当前深度
    this.$vnode.data.routerView = true;

    let depth = 0;
    let parent = this.$parent;
    while (parent) 
      const vnodedata = parent.$vnode && parent.$vnode.data;
      if (vnodedata) {
        if (vnodedata.routerView) {
          // 说明当前parent是一个router-view
          depth++;
        }
      }
      parent = parent.$parent;
    }
    // 获取匹配path的component
    let component = null;
    const route = this.$router.matched[depth];
    if (route) {
      component = route.component;
    }
    return h(component);
  },
}

这一部分的重点在于while循环查找,当前的this指向路由显示页面的router-view组件,通过循环不断的向上查找从而确定路由的深度,还是要多加思考和理解。

App组件 2

div#app 3

a# 4

a#/about 5

about组件 6

div.about 7

router-view 8

上一篇:vue的编辑


下一篇:Vue路由回退的完美解决方案(vue-route-manager)