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