简单的vue-router实现

模拟vue-router实现简单的路由功能, 仿照vue-router使用的方法, 在router/index.js中配置路由文件从而逐步实现目标.

  1. 实现简易的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)

  2. 【简单的vue-router实现】此时运行会发现报错, 提醒还需要定义 router-linkrouter-view
    Vue.component('router-link', { props: [ 'to' ], // 无法编译模板,需要使用render函数router-link或者 jsx // template: 'router-link', render(h) { return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default) }, }) Vue.component('router-view', { render(h) { return h(null) } })

  3. 定义current, 记录当前路由地址. 监听 hashchange 事件, 路由变化即时更新从而重新渲染 router-view 的内容.
    class PVueRouter { constructor(options){ this.$options = optionsVue.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个层级的路由组件.

    推荐阅读