vue-router原理

652 阅读1分钟

Vue Router是vue.js官方的路由管理器,它和vue.js的核心深度集成,让构建单页面应用变得简单

一.安装

 vue add router

二.核心步骤

步骤一:使用vue-router插件,router.js

import Router from 'vue-router'
Vue.use(Router)
// VueRouter是插件,使用插件必须使用use方法,
// 使用this.$router可以访问Router实例,即在内部Vue.prototype.$router
// 实现并注册两个全局组件<router-view>和<router-link>

步骤二:创建Router实例,router.js

export default new Router({...})

步骤三:在根组件上添加该实例

 // main.js
import router from './router'
new Vue({
  router,
}).$mount("#app");

步骤四:添加路由视图,App.vue

<router-view></router-view>

步骤五:导航

<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>

二.vue-router 源码实现

需求分析

  1. 作为一个插件实现VueRouter类和install方法
  2. 实现2个全局组件,router-view用于显示匹配组件内容,router-link用于跳转
  3. 监控url变化:监听hashchange或popstate
  4. 响应最新url,创建一个响应式的curren,当它改变时获取对应组件并显示
// 引用传入Vue构造函数
let Vue

// VueRouter类: new VueRouter({routes: [...]})
class VueRouter {
  constructor(options) {
    // 保存选项备用
    this.$options = options

    // 处理routes,缓存path和route的映射关系
    this.routeMap = {}
    this.$options.routes.forEach(route => {
      this.routeMap[route.path] = route
    })

    // 创建current保存当前url
    // 为了让使用current的组件重新渲染
    // 他应该是响应式的
    Vue.util.defineReactive(this, 'current', '/')

    // 监听hashchange事件
    window.addEventListener('hashchange', this.onHashChange.bind(this))
    window.addEventListener('load', this.onHashChange.bind(this))
  }

  onHashChange() {
    // 修改当前url, hash的格式#/xxx
    this.current = window.location.hash.slice(1)
    console.log(this.current);

  }
}

// 实现install方法
// 实现静态install方法即可
// 参数1:Vue构造函数,Vue.use(VueRouter)
VueRouter.install = function (_Vue) {
  Vue = _Vue

  // 1.挂载VueRouter实例
  // 为了能够拿到Vue根实例中的router实例
  // 可以利用全局混入
  Vue.mixin({
    beforeCreate() {
      // 上下文已经是组件实例了
      if (this.$options.router) {
        Vue.prototype.$router = this.$options.router
      }
    }
  })


  // 2.注册两个组件router-view,router-link
  Vue.component('router-view', {
    render(h) {
      // console.log('router-view render', this.$router.current);
      // 获取路由实例
      // const routes = this.$options.routes
      // const current = this.$router.current
      // const route = routes.find( route => route.path === current)
      // const comp = route ? route.component : null
      // 从缓存中取路由实例
      const {routeMap, current} = this.$router
      const component = routeMap[current] ? routeMap[current].component : null
      return h(component)
    }
  })

  // <router-link to="/">xxx</router-link>
  Vue.component('router-link', {
    props: {
      to: {
        type: String,
        default: ''
      },
    },
    render(h) {
      // 参数1tag类型
      // 参数2传入各种属性和事件
      return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default)
      // 也可以使用jsx
      // return <a href={'#' + this.to}>{this.$slots.default}</a>
    }
  })
}

export default VueRouter