1. 程式人生 > 其它 >手寫router(簡單實現巢狀路由)

手寫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;