模仿 vue-router
实现简略的路由性能, 仿照 vue-router
应用的办法, 在 router/index.js
中配置路由文件从而逐渐实现目标.
-
实现繁难的
PVueRouter
类, 首先实现动态install
办法, 保障Vue.use(Router)
这一步失常运行. 并挂载到组件中的 $router 属性let Vue // 定义 Vue 变量, 在 install 办法中赋为真正的构造函数应用 class PVueRouter {constructor(options){ this.$options = options // 为了不便, 在此处将路由实例赋给 Vue 原型, 这样在路由组件内能够通过 this.$router 拜访. 与上面的 mixin 同样作用 Vue.prototype.$router = this } // 静态方法 install static install(_Vue){ Vue = _Vue // 工作 1: 挂载 $router 或者应用 mixin 在根组件混入以后路由实例 Vue.mixin({beforeCreate() { // 只有根组件领有 router 选项 if (this.$options.router) { // vm.$router Vue.prototype.$router = this.$options.router; } } }); Vue.component('router-link', RouterLink) Vue.component('router-view', RouterView) // 首先要定义 router-link 及 router-view 组件 } } // import Router from 'pvue-router' // 引入简易版自定义的 router 类 // Vue.use(Router)
-
此时运行会发现报错, 揭示还须要定义
router-link
及router-view
Vue.component('router-link', {props: [ 'to'], // 无奈编译模板, 须要应用 render 函数 <a href="#/about">router-link</a> 或者 jsx // template: '<a>router-link</a>', render(h) { return h('a', { attrs: {href: '#' + this.to} }, this.$slots.default) }, }) Vue.component('router-view', {render(h) {return h(null) } })
-
定义
current
, 记录以后路由地址. 监听hashchange
事件, 路由变动即时更新从而从新渲染router-view
的内容.class PVueRouter {constructor(options){ this.$options = options Vue.util.defineReactive(this, 'current', window.location.hash.slice(1) || '/') window.addEventListener('hashchange', () => {this.current = window.location.hash.slice(1) || '/' }) this.routeMap = {} this.$options.routes.forEach(route => {this.routeMap[route.path] = route.component }); Vue.prototype.$router = this } Vue.component('router-view', {render(h) {const component = routeMap[current] || null; return h(component); } })
至此实现了简略的路由性能, 然而当呈现嵌套路由时, 就会发现 Maximum call stack size exceeded
. 因为外部又嵌套了 router-view
, 所以渲染路由对应的组件时会有限套娃 ……
比方以后路由地址为 '/about/info'
, 对应AboutInfo
组件; 其父级为 '/about'
, 对应 About
组件. 须要对其进行深度标记, 并应用 matched 代替 current 属性, 因为须要别离渲染 2 个层级的路由组件.