这篇手写VueRouter学不会我回家养猪仔

70 阅读1分钟

R-C.jpg

手写vue-router

定义2个类 VueRoutr、 HistoryRouter

1、new VueRouter 传入options

2、判断路由模式

3、通过window监听hashchange的改变,截取当前路由的hash值,并把存到当前的hash值存到HistoryRouter实例中

let Vue = null;

class HistoryRoute {  
  constructor() {
    this.current = null; // 记录当前路由
  }
}


class VueRouter {
  constructor(options) {
    this.mode = options.mode || 'hash';// 记录router的模式
    this.routes = options.routes || []; // 记录路由表
    this.history = new HistoryRoute(); // 记录当前路由
    this.routesMap = this.createMap(this.routes); // 将路由表转换成键值对
    
    // 初始化路由
    this.init();
  }
  
  // 初始化路由
  init() {

    // hash模式
    if(this.mode === 'hash'){
      location.hash ? '' : location.hash = '/';
      
      // 监听页面重新加载,将当前路由赋值给history.current
      window.addEventListener('load', () => {
        this.history.current = location.hash.slice(1);
      })

      // 监听hash值变化,将当前路由赋值给history.current
      window.addEventListener('hashchange', () => {
        this.history.current = location.hash.slice(1);
      } )
    } else {

      // 待定问题
    
    }
  } 

  // 将路由表变成键值对
  createMap (routers) {
    const map = routers.reduce((pre, current) => {
      pre[current.path] = current.component;
      return pre
    },{})
    debugger
    return map
  }
}

实现 VueRouter.install函数

  1. 用混入, 在组件生成前(beforeCreate中) 把当前路由变成响应式的(如果当前路由hash值改变时, 全局组件router-view会重新获取新path对应的组件,并进行渲染)

  2. 在组件生成前(beforeCreate中) 实现 $router 和 $route

  3. 注册全局组件 router-link

  4. 注册全局组件 router-view

VueRouter.install = function (v) { 
  Vue = v;

  // 混入
  Vue.mixin({
    beforeCreate() {

      if (this.$options && this.$options.router){
        // 根组件
        this._root = this;
        this._router = this.$options.router;
        
        // 将当前路由变成响应式的
        Vue.util.defineReactive(this, 'xxx', this._router.history)

      } else {
        // 子组件
        this._root = this.$parent && this.$parent._root;
        this._router = this.$parent && this.$parent._router;
      }

      // this.$router.push('/home');
      Object.defineProperty(this, '$router', {  
        get() {
          return this._router
        }
      })
     
      // 返回当前路由
      Object.defineProperty(this, '$route', {  
        get() {
          return this._router.history.current
        }
      })
    }
  });

  // 注册全局组件 router-link
  Vue.component('router-link', {
    props: {  
      to: String
    },
    render(h) {
      return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default)
    },
  })

  // 注册全局组件 router-view
  Vue.component('router-view', {

    render(h) {
      const current = this._self._root._router.history.current;
      const routesMap = this._self._root._router.routesMap
      return h(routesMap[current])
    }
  })
    
}