Vue-router 简单实现

2019-11-11  本文已影响0人  Sommouns
class HistoryRoute {
  constructor() {
    this.current = null
  }
}

class VueRouter {
  constructor(options) {
    this.mode = options.mode || 'hash'
    this.routes = options.routes || []
    this.routesMap = this.createMap(this.routes)

    this.history = new HistoryRoute()
    this.init()
  }
  init() {
    if (this.mode === 'hash') {
      if (!location.hash) {
        location.hash = '/'
      }
      window.addEventListener('load', () => {
        console.log('load')
        this.history.current = location.hash.slice(1)
      })
      window.addEventListener('hashchange', () => {
        console.log('hashchange')
        this.history.current = location.hash.slice(1)
      })
    } else {
      if (location.hash) {
        location.pathname = '/'
      }
      window.addEventListener('load', () => {
        console.log('load')
        this.history.current = location.pathname
      })
      window.addEventListener('popstate', () => {
        console.log('popstate')
        this.history.current = location.pathname
      })
    }
  }
  createMap(routes) {
    return routes.reduce((memo, current) => {
      memo[current.path] = current.component
      return memo
    }, {})
  }
  go() {

  }
  push(path) {
    window.history.pushState({}, '', path)
    this.history.current = path
  }
  back() {

  }
  afterEach() {
    console.log('after')
  }
  beforeEach() {

  }
}
VueRouter.install = function (Vue) {
  console.log(Vue, 'install')

  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 { // 子节点
        try {
          this._root = this.$parent._root
        } catch (e) {
          console.log(this, e)
        }
      }
      Object.defineProperty(this, '$router', {
        get() {
          return this._root._router
        }
      })
      Object.defineProperty(this, '$route', {
        get() {
          return {
            current: this._root._router.history.current
          }
        }
      })
    }
  })
  Vue.component('router-link', {
    props: {
      to: String,
      tag: String
    },
    render(h) {
      let mode = this._self._root._router.mode
      let tag = this.tag || 'a'
      console.log(this)
      return h(tag, {
        attrs: {
          href: this._self._root._router.mode === 'hash' ? `#${this.to}` : this.to,
        },
        on: {
          click: () => {
            this.handleClick()
          }
        }
      }, this.$slots.default)
    },
    methods: {
      handleClick() {
        this._root._router.push(this.to)
        event.returnValue = false
      }
    }
  })
  Vue.component('router-view', {
    render(h) {
      let current = this._self._root._router.history.current
      let routeMap = this._self._root._router.routesMap
      console.log(this)

      return h(routeMap[current])
    }
  })
}
export default VueRouter

上一篇下一篇

猜你喜欢

热点阅读