当前位置: 首页 > 工具软件 > vue-blog > 使用案例 >

学习blog之简单vue-router实现

锺离德庸
2023-12-01

vue-router的实现原理大概如下:
1.通过用户传入的路由数组生成对应的路由表
2.在install方法中对vue进行全局混入,定义响应式属性_route,方便触发vue的更新
3.通过addEventListener监听hash的改变,或者支持h5的话优先使用pushState(在本文代码中没有使用)
4.实现router-link和router-view组件

代码如下,方便各位理解vue-router这个插件~

let _Vue
let isInstall

export default class VueRouter {

  constructor(options) {
    // 根实例
    this.root = null
    // 路由表
    this.routes = options.routes
    // vue-router记录的当前路由
    this.current = getHashPath()
  }

  // 让vue-router记录下当前的根实例
  // 监听url hash改变
  init(vm) {
    this.root = vm
    window.addEventListener('hashchange', () => {
      this.current = getHashPath()
      // 触发视图更新
      this.root._route = this.current
    })
  }

  // this.$router.push
  push(path) {
    window.location.hash = path
  }

  static install(Vue) {

    // 防止重复实例化
    if (isInstall && _Vue === Vue) return
    _Vue = Vue
    isInstall = true

    Vue.mixin({
      beforeCreate() {
        // 说明是根实例,需要做处理
        if (this.$options.router) {
          // _routerRoot保存的是根实例,所有的vm属性都会有
          this._routerRoot = this
          // 这是vue-router实例
          this._router = this.$options.router
          this._router.init(this)
          // 增加响应式
          Vue.util.defineReactive(this, '_route', this._router.current)
        } else {
          this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
        }
      },
    })

    Object.defineProperty(Vue.prototype, '$router', {
      get () { return this._routerRoot._router }
    })

    // router-link 组件实现
    Vue.component('router-link', {
      props: {
        to: String
      },
      render() {
        return (
          <span onClick={this.handleClick}>{ this.$slots.default }</span>
        )
      },
      methods: {
        handleClick() {
          window.location.hash = this.to
        }
      }
    })

    // router-view组件实现
    Vue.component('router-view', {
      render(h) {
        const routes = this.$router.routes
        // 这里有用到我们之前设置的响应式属性
        // 当触发Vue更新时
        // Vue就会重新渲染这个组件的render函数
        let route = this._routerRoot._route
        const currentRoute = routes.find(item => item.path === route)
        if (!currentRoute) {
          return (
            <div>未找到</div>
          )
        }
        return h(currentRoute.component)
      }
    })
  }
}

function getHashPath() {
  return window.location.hash.slice(1) || '/'
}
 类似资料: