Table of Contents generated with DocToc
vue-router实现思路
-
插件insatll
- Vue.prototype.$router
- 声明全局组件router-view router-link
- router-view: this.$router.current => component => h(component)
- router-link: h('a', {attrs: {href:'#'+this.to}, this.$slots.default})
-
VuerRouter逻辑
- url监听:
- window.addEventListener("hashchange", this.onHashChange.bind(this));
- window.addEventListener("onload", this.onHashChange.bind(this));
- current: Vue.util.defineReactive(this, "current", window.location.hash.slice(1) || "/");
- url监听:
-
vue-router 嵌套路由的解决方式
- router-view 深度标记 depth
- 路由匹配时获取代表深度的matched数组
-
代码块
// 1.插件 // 2.两个组件 // vue插件: // function // 要求必须有一个install,将来会被Vue.use调用 let Vue; // 保存Vue构造函数,插件中要使用,不导入还能用 class VueRouter { constructor(options) { this.$options = options; // this.current = window.location.hash.slice(1) || '/' // const initial = window.location.hash.slice(1) || "/"; // Vue.util.defineReactive(this, "current", initial); this.current = window.location.hash.slice(1) || "/"; Vue.util.defineReactive(this, "matched", []); // match方可以递归遍历路由表,获得匹配关系数组 this.match(); // this.routeMap = {}; // options.routes.forEach(route => { // this.routeMap[route.path] = route.component; // }); window.addEventListener("hashchange", this.onHashChange.bind(this)); window.addEventListener("onload", this.onHashChange.bind(this)); } onHashChange() { this.current = window.location.hash.slice(1) || "/"; this.matched = []; this.match(); } match(routes) { routes = routes || this.$options.routes; // 遍历递归 for (const route of routes) { if (route.path === "/" && this.current === "/") { this.matched.push(route); return; } // /about/info if (route.path !== "/" && this.current.includes(route.path)) { this.matched.push(route); if (route.children && route.children.length) { this.match(route.children); } return; } } } } // 参数1是Vue.use调用时传入的 VueRouter.install = function(_Vue) { Vue = _Vue; // console.log(this) // 1.挂载$router属性 // this.$router.push() // 全局混入目的:延迟下面逻辑到router创建完毕并且附加到选项上时才执行 Vue.mixin({ beforeCreate() { // 次钩子在每个组件创建实例时都会调用 // 根实例才有该选项 if (this.$options.router) { Vue.prototype.$router = this.$options.router; } } }); // 2.注册实现两个组件router-view,router-link Vue.component("router-link", { props: { to: { type: String, required: true } }, render(h) { // return <a href={'#'+this.to}>{this.$slots.default}</a> return h("a", { attrs: { href: `#${this.to}` } }, this.$slots.default); } }); Vue.component("router-view", { render(h) { // let component = null; // const route = this.$router.$options.routes.find( // route => route.path === this.$router.current // ); // console.log(route, this.$router.routeMap, this.$router.current); // if (route) { // component = route.component; // } // console.log(this.$router.current); // 标记当前router-view深度 this.$vnode.data.routerView = true; let depth = 0; let parent = this.$parent; while (parent) { const vnodeData = parent.$vnode ? parent.$vnode.data : {}; if (vnodeData.routerView) { // 说明当前parent是一个router-view depth++; } parent = parent.$parent; } // 获取path相应的组件 // const component = this.$router.routeMap[this.$router.current]; let component = null; const route = this.$router.matched[depth]; if (route) { component = route.component; } return h(component); } }); }; export default VueRouter;