mario-mui / blog

0 stars 0 forks source link

深入理解一下vue-router #2

Open mario-mui opened 5 years ago

mario-mui commented 5 years ago

路由模式

ps 当前源码commit vue-router 提供了三种运行模式:

官网的例子来看看vue-router 如何运作的

<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

<div id="app">
  <h1>Hello App!</h1>
  <p>
    <router-link to="/foo">Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
  </p>
  <router-view></router-view>
  <script>
    const Foo = { template: '<div>foo</div>' }
    const Bar = { template: '<div>bar</div>' }
    const routes = [
      { path: '/foo', component: Foo },
      { path: '/bar', component: Bar }
    ]

    const router = new VueRouter({
      routes
    })
    const app = new Vue({
      router
    }).$mount('#app')

  </script>
</div>

class VueRouter

主要这里定义了 router 的各种熟悉。常见的如大家所知

  //比如设置mode 为 'history' 默认情况为hash(本文所说的模式), 设置 routes熟悉
  options: RouterOptions;
 //vue-router 实现的三种模式
  mode: string;
  history: HashHistory | HTML5History | AbstractHistory;
  // 匹配路由的matcher
  matcher: Matcher;
  fallback: boolean;
  // 各种钩子方法
  beforeHooks: Array<?NavigationGuard>;
  resolveHooks: Array<?NavigationGuard>;
  afterHooks: Array<?AfterNavigationHook>;

vue.install(VueRouter)

默认浏览器下会自动安装 router 地址

  1. 设置了 _route 响应式属性
  2. 使用两个组件为上面的 <router-link> 和 <router-view> 这两个组件的作用大家在使用时候相信已经知道了。接下来我们要说的是如何点击 使得 变化的
  3. 当我们点击

    
    const handler = e => {
      if (guardEvent(e)) {
        if (this.replace) {
          router.replace(location)
        } else {
          router.push(location)
        }
      }
    }
    
    const on = { click: guardEvent }
    if (Array.isArray(this.event)) {
      this.event.forEach(e => { on[e] = handler })
    } else {
      on[this.event] = handler // this.event 默认为click
    }
[源码](https://github.com/vuejs/vue-router/blob/dev/src/components/link.js#L75)
会触发 [router.push ](https://github.com/vuejs/vue-router/blob/dev/src/components/link.js#L66) [router就是](https://github.com/vuejs/vue-router/blob/dev/src/install.js#L38)

push (location: RawLocation, onComplete?: Function, onAbort?: Function) { this.history.push(location, onComplete, onAbort) }

[源码](https://github.com/vuejs/vue-router/blob/dev/src/index.js#L153)
当前history 咱们是默认的hash 模式

push (location: RawLocation, onComplete?: Function, onAbort?: Function) { const { current: fromRoute } = this this.transitionTo(location, route => { pushHash(route.fullPath) handleScroll(this.router, route, fromRoute, false) onComplete && onComplete(route) }, onAbort) }

[源码](https://github.com/vuejs/vue-router/blob/dev/src/history/hash.js#L47)

transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) { const route = this.router.match(location, this.current) this.confirmTransition(route, () => { this.updateRoute(route) onComplete && onComplete(route) this.ensureURL()

  // fire ready cbs once
  if (!this.ready) {
    this.ready = true
    this.readyCbs.forEach(cb => { cb(route) })
  }
}, err => {
  if (onAbort) {
    onAbort(err)
  }
  if (err && !this.ready) {
    this.ready = true
    this.readyErrorCbs.forEach(cb => { cb(err) })
  }
})

}

[源码](https://github.com/vuejs/vue-router/blob/dev/src/history/base.js#L64)
会走调到 this.updateRoute(route)

updateRoute (route: Route) { const prev = this.current this.current = route this.cb && this.cb(route) this.router.afterHooks.forEach(hook => { hook && hook(route, prev) }) }

其中将会调用 `this.cb(route)`
this.cb 是什么时候设置的呢。

history.listen(route => { this.apps.forEach((app) => { app._route = route }) })


[源码](https://github.com/vuejs/vue-router/blob/dev/src/index.js#L126-L130)
会去设置 app._route, 我们知道 app._route 是响应式的。会触发 render 函数。从而触发 router-view 的[render行数](https://github.com/vuejs/vue-router/blob/dev/src/components/view.js#L13)
最后回去创建[comment](https://github.com/vuejs/vue-router/blob/dev/src/components/view.js#L54)
然后就是vue 的re-render 从而达到router 的效果
mario-mui commented 5 years ago

image