vue-router的实现原理并简单手写实现

119 阅读1分钟

vue-router的实现原理

hash原理

  • 将url#后的内容作为路径地址
  • 监听hashchange事件
  • 通过当权路由地址找到对应组件重新渲染

history原理:

  • 通过history.pushstate() 改变地址栏
  • 监听popstate事件
  • 通过当前路由地址找到对应组件重新渲染

代码实现

从代码中可以看出

  1. VueRouter是一个构造函数,有个install静态方法,当Vue.use(VueRouter)时执行
  2. VueRouter的构造器接收一个对象为参数,这个对象包括mode和routes等属性
  3. 创建Vue实例时,将VueRouter实例作为参数传入,使Vue可直接调用 routeroute 和router
  4. VueRouter 有两个自定义组件,router-link、router-view

VueRouter类图

简单实现history模式代码

export default class VueRouter{

  option = null
  data = null
  routerMap = null

  static install(Vue) {
    // 用mixin混入,将$router、$route属性添加到的vue实例
    Vue.mixin({
      beforeCreate() {
        if (this.$options.router) {
          Vue.prototype.$router = this.$options.router
          this.$options.router.init(Vue)
        }
      }
    })
  }

  constructor(option) {
    this.option = option
    this.routerMap = {}
    this.data = {}
  }

  // 初始化
  init(Vue) {
    // 将data 变为响应式
    this.data = Vue.observable({current: window.location.pathname})
    this.initRouteMap()
    this.initComonents(Vue)
    this.initEvent()
  }

  // 初始化routeMap,将路由地址和路由组件对应,方便切换路由时获取组件
  initRouteMap(){
    console.log(this.option.routes);
    this.option.routes.forEach(element => {
      this.routerMap[element.path] = element.component
    });
  }

  // 初始化自定义组件router-link、router-view
  initComonents(Vue) {
    let self = this
    Vue.component('router-link', {
      props: {
        to: String
      },
      render(h) {
        return h('a', {
          attr: {
            href: this.to
          },
          on: {
            click: (e) => {
              // 阻止a标签的默认事件,用history.pushState来改变地址栏
              history.pushState(null, "", this.to)
              // data是响应式的,当data.current改变时,触发router-view的改变
              self.data.current = this.to
              e.preventDefault()
            }
          }
        }, [this.$slots.default])
      }
    })
     Vue.component('router-view', {
      render(h) {
        return h(self.routerMap[self.data.current])
      }
    })
  }

  // 初始化事件,监听popState 事件,当浏览器切换历史路径(后退、前进)时触发,切换组件
  initEvent() {
    // 通过router-link切换路由时,不会触发popstate
    window.addEventListener('popstate', () => {
      this.data.current = window.location.pathname
    })
  }
}