手写router(简单实现嵌套路由)

手写router(简单实现嵌套路由)

需求分析: 简单实现嵌套路由

  • ① 记录当前路由的深度depth
  • ② 路由匹配,得到深度对应的组件

代码实现

// 简单实现嵌套路由
// ① 记录当前路由router-view的深度
// ② 路由匹配,得到深度对应的组件

let Vue;

class Router {
  constructor(options) {
    this.$options = options;
    this.routeMap = {};
    // options.routes.forEach((route) => {
    //   this.routeMap[route.path] = route;
    // });
    // Vue.util.defineReactive(this, "current", window.location.hash.slice(1) || "/");
    this.current = window.location.hash.slice(1) || "/";
    window.addEventListener("hashchange", this.onHashchange.bind(this));
    window.addEventListener("load", this.onHashchange.bind(this));
	// 响应式数组
    Vue.util.defineReactive(this, "matched", []);
    this.match();
  }

  onHashchange() {
    this.current = window.location.hash.slice(1);
	// 页面刷新时,需要将matched数组置空,重新匹配路由
    this.matched = [];
    this.match();
  }
  // 通过 this.current 来匹配路由
  match(routes) {
    routes = routes || this.$options.routes;
    for (const route of routes) {
      if (route.path === "/" && this.current === "/") {
        this.matched.push(route);
        return;
      }
      // this.current : /about/info , route.path : /about 、 /about/info
      if (route.path !== "/" && this.current.includes(route.path)) {
        this.matched.push(route);
        if (route.children) {
          this.match(route.children);
        }
        return;
      }
    }
    console.log(this.matched)
  }

  static install(_Vue) {
    Vue = _Vue;
    Vue.mixin({
      beforeCreate() {
        if (this.$options.router) {
          Vue.prototype.$router = this.$options.router;
        }
      },
    });
    Vue.component("router-link", {
      props: {
        to: {
          type: String,
          default: "",
        },
      },
      render(h) {
        return h("a", { attrs: { href: "#" + this.to } }, this.$slots.default);
      },
    });

    Vue.component("router-view", {
      render(h) {
        // const { routeMap, current } = this.$router;
        // console.log(current);
        // const comp = (routeMap[current] && routeMap[current].component) || null;
		
	// 计算出路由的深度
        this.$vnode.data.routerView = true;
        let depth = 0;
        let parent = this.$parent;
        while (parent) {
          const vnodeData = parent.$vnode && parent.$vnode.data;
          // parent的$vnode.data.routerView存在,即该parent组件也是一个router-view,那么组件的深度就要➕1
          if (vnodeData && vnodeData.routerView) {
            depth++;
          }
          parent = parent.$parent;
        }

        const route = this.$router.matched[depth]
        const comp = route && route.component || null
        return h(comp);
      },
    });
  }
}

export default Router;
posted @ 2021-06-10 21:12  shine_lovely  阅读(146)  评论(0编辑  收藏  举报