手寫router(簡單實現巢狀路由)
阿新 • • 發佈:2021-06-10
手寫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;