vue-router

139 阅读1分钟

vue-router

const router = new VueRouter({ routes })
Vue.use(VueRouter)
new Vue({ router })

实例化VueRouter

// 传入路由表
[
  {
    path: '/demo',
    components: {
      default: Default,
      name1: Name1,
    },
    children: [{}...],
    // 守卫
  }
]

1. this.matcher = createMatcher(options.routes || [], this) 构建record树
const record: RouteRecord = {
  // 当前路由对应的路径
  path,  
  // 当前路由渲染的组件对象     
  components: { default: route.component }, 
  // 当前这条路由对应的组件实例
  instances: {}, 
  enteredCbs: {},
  // 父路由
  parent, 
  redirect: route.redirect,
  // 守卫钩子
  beforeEnter: route.beforeEnter, 
}
match方法: 根据当前url匹配所有相关路由

2. 全局守卫
this.beforeHooks = []
this.resolveHooks = []
this.afterHooks = []

3. this.history = new HTML5History(this, options.base)
this.current = START // 一条route
route: Route = {
  path: location.path || '/',
  hash: location.hash || '',
  // 参数
  query,
  params: location.params,
  fullPath,
  // 很重要,由父到子的路由record
  matched: record ? formatMatch(record) : []
}
record概念:根据路由表创建 (路径对应组件)
route概念: 根据当前url创建(path query params matched)

Vue.use(VueRouter) 注册插件 执行插件的install方法

// 通过mixin方法混入 beforeCreate 钩子:

// 根组件时执行
this._routerRoot = this
// VueRouter实例(matcher history)
this._router = this.$options.router
// 初始化操作
this._router.init(this)
// 响应式_route,后面更改的时候触发重新渲染
Vue.util.defineReactive(this, '_route', this._router.history.current)

// Vue原型上定义
$router  this._routerRoot._router 为了提供 push replace 等方法
$route   this._routerRoot._route 为了获得当前路由相关的信息 (params query等)

// 注册组件
RouterView  RouterLink

router.init

history.transitionTo(最新的url, cb1)
// 根据url 获取route,值得注意的是属性matched: [父record,子record]

// 守卫
confirmTransition(route, cb2) // 根据route 和 current 得到 deactivated activated updated  
1.extractLeaveGuards(deactivated)    // 失活组件的 beforeRouteLeave
2.router.beforeHooks                 // 所有的失活组件已离开,即将进入更新
3.extractUpdateHooks(updated)        // 更新组件的钩子
4.activated.map(m => m.beforeEnter)  // 即将enter的组件的配置钩子
5.resolveAsyncComponents(activated)  // 即将enter的组件, 看下是否是异步组件(异步next)
6.extractEnterGuards(activated)      // 组件enter钩子(注意: enter的组件获取不到实例)next(ins => {})
7.router.resolveHooks                // resolveHooks

// runQueue
执行每个钩子函数,传入 route(路由信息) , current, next方法
调用next才会step向下 next() next(false) next(newPath)

8.this.current = route               //此时浏览器url还未更新
9.window.addEventListener('popstate', handleRoutingEvent: 执行transitionTo)
10.this.ensureURL()                  // 更改url 如果不是初次渲染,这个时候开始更新组件 
11.router.afterHooks                 // 守卫结束
12.history.listen                    // 监听路由变化

RouterView

/*
  在生成 <router-view></router-view> vnode的时候,发现组件配置 functional 为true
  执行组件配置的render方法
*/


render(_, { props /* name该路由对应的组件,默认default */, children, parent/* 父vm */, data }) {
  const name = props.name || 'default'
  const route = parent.$route
  data.routerView = true
  // 遍历所有parent组件
  if (vnodeData.routerView) {
    depth++
  } 
  const matched = route.matched[depth]
  const component = matched && matched.components[name]
  // 返回对应的组件vnode
  h(component, data, children)
}