简单的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. 此时运行会发现报错, 提醒还需要定义 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 = 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个层级的路由组件.

你可能感兴趣的:(vue-router)