VueRouter源码详细解读

路由模式

1. hash

使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器。
Hash URL,当 # 后面的哈希值发生变化时,不会向服务器请求数据,可以通过 hashchange 事件来监听到 URL 的变化,从而进行跳转页面。

2. history

依赖 HTML5 History API 和服务器配置

3. abstract

支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式。

router调用

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/views/Home.vue'
import Demo from '@/views/Demo.vue'
import InstantMessager  from '@/views/InstantMessager'
import Seller  from '@/views/Seller'
Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/demo',
    name: 'Demo',
    component: Demo,
    meta: {
      isFullPage: true
    }
  },
  {
    path: '/instantMessager',
    name: 'InstantMessager',
    component: InstantMessager,
  },
  {
    path: '/seller',
    name: 'Seller',
    component: Seller,
    meta: {
      isFullPage: true
    }
  },
]
const router = new VueRouter({
  mode: '',
  base: process.env.BASE_URL,
  routes
})

export default router

源码解析

1. Install

Vue.use(VueRouter)会执行install方法
1、在beforeCreated中初始化vue-router,并将_route响应式
2、在 Vue 原型上添加 r o u t e r 属 性 ( V u e R o u t e r ) 并 代 理 到 t h i s . router 属性( VueRouter )并代理到 this.router属性(VueRouter)并代理到this.root._router
3、Vue上注册router-link和router-view两个组件

export function install (Vue) {
  if (install.installed && _Vue === Vue) return
  install.installed = true

  _Vue = Vue

  const isDef = v => v !== undefined

  const registerInstance = (vm, callVal) => {
    let i = vm.$options._parentVnode
    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
      i(vm, callVal)
    }
  }

  Vue.mixin({
    beforeCreate () {
      if (isDef(this.$options.router)) {
        this._routerRoot = this
        this._router = this.$options.router
        this._router.init(this)
        Vue.util.defineReactive(this, '_route', this._router.history.current)
      } else {
        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
      }
      registerInstance(this, this)
    },
    destroyed () {
      registerInstance(this)
    }
  })

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

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

  Vue.component('RouterView', View)
  Vue.component('RouterLink', Link)

  const strats = Vue.config.optionMergeStrategies
  // use the same hook merging strategy for route hooks
  strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}
2. router实例

生成实例过程中,主要做了以下两件事
1、根据配置数组(传入的routes)生成路由配置记录表。
2、根据不同模式生成监控路由变化的History对象

首先我们看到在new VueRouter()的时候传入的参数,比如mode,base,routes等。mode是导航模式,有hash(默认),history,abstract。
hash 是默认值,如果不传入或者浏览器不支持history时,就用hash。

class VueRouter {
  constructor (options: RouterOptions = {}) {
    this.app = null
    this.apps = []
    this.options = options
    this.beforeHooks = []
    this.resolveHooks = []
    this.afterHooks = []
    this.matcher = createMatcher(options.routes || [], this)
    let mode = options.mode || 'hash'
    this.fallback =
      mode === 'history' && !supportsPushState && options.fallback !== false
    if (this.fallback) {
      mode = 'hash'
    }
    if (!inBrowser) {
      mode = 'abstract'
    }
    this.mode = mode

    switch (mode) {
      case 'history':
        this.history = new HTML5History(this, options.base)
        break
      case 'hash':
        this.history = new HashHistory(this, options.base, this.fallback)
        break
      case 'abstract':
        this.history = new AbstractHistory(this, options.base)
        break
      default:
        if (process.env.NODE_ENV !== 'production') {
          assert(false, `invalid mode: ${mode}`)
        }
    }
  }

1). createMatcher
根据routes数组,做一个映射,返回match、addRoutes 、addRoute、getRoutes 方法。

 this.matcher = createMatcher(options.routes || [], this)

// 方法createMatcher:
export function createMatcher (
  routes: Array,
  router: VueRouter
): Matcher {
  const { pathList, pathMap, nameMap } = createRouteMap(routes)

  function addRoutes (routes) { }
  function addRoute (parentOrRoute, route) {}
  function getRoutes () {  }

  function match {  }
  return {
    match,
    addRoute,
    getRoutes,
    addRoutes
  }
}

VueRouter源码详细解读_第1张图片

2)createRouteMap, 创建路由映射表, 路径/名称的映射表,生成路由记录(route records);

 const { pathList, pathMap, nameMap } = createRouteMap(routes)

路由记录属性如下:

const record: RouteRecord = {
    path: normalizedPath,
    regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),
    components: route.components || { default: route.component },
    alias: route.alias
      ? typeof route.alias === 'string'
        ? [route.alias]
        : route.alias
      : [],
    instances: {},
    enteredCbs: {},
    name,
    parent,
    matchAs,
    redirect: route.redirect,
    beforeEnter: route.beforeEnter,
    meta: route.meta || {},
    props:
      route.props == null
        ? {}
        : route.components
          ? route.props
          : { default: route.props }
  }

如某一条路由记录
VueRouter源码详细解读_第2张图片
createRouteMap为每条路由生成路由记录,结果如下:
VueRouter源码详细解读_第3张图片
2)判断mode的值,根据不同的mode走不同的方法,
若浏览器不支持HTML5History方式(通过supportsPushState变量判断),则mode强制设为’hash’;若不是在浏览器环境下运行,则mode强制设为’abstract’

点击跳转主线:

this.$router.push(’/demo’) ->History.push -> transitionTo -> match -> createRoute -> confirmTransition -> updateRoute-> render

VueRouter源码详细解读_第4张图片

createRoute
VueRouter源码详细解读_第5张图片

你可能感兴趣的:(vue,vue.js,javascript,前端)