Vue 路由 Vue-Router

路由

注入實(shí)例
const router = new VueRouter({
  routes : [
    { path: '/user', name: 'user' , component:  { template: '<div>User</div>' },
    { path: '/user/:id', 
       component: { template: '<div>{{ $route.params.id }}</div>' }
    }
  ]
})
new Vue({
  router
}).$mount('#app')

此后可以在任何組件內(nèi)通過(guò) this.$router 訪(fǎng)問(wèn)路由器(或通過(guò)import導(dǎo)入router實(shí)例來(lái)訪(fǎng)問(wèn)),通過(guò) this.$route 訪(fǎng)問(wèn)當(dāng)前路由(包括query,hash等)

路由參數(shù)

通過(guò):標(biāo)記路由參數(shù),組件內(nèi)可通過(guò)$route.params訪(fǎng)問(wèn)該參數(shù)。
使用props可以將組件和路由解耦,使組件不再只能在特定URL下使用。

嵌套路由

如下,當(dāng) /main 匹配成功,Main會(huì)被渲染,同時(shí) MainDefault 會(huì)被渲染在 Main 的<router-view> 中。當(dāng)/main/dashboard 匹配成功,Dashboard 會(huì)被渲染在 Main 的<router-view> 中

{
  path: '/main',
  name: 'main',
  component: Main,
  children: [
    { path: '', component: MainDefault },
    {
      path: 'dashboard',
      component: Dashboard
    }
  ]
}
捕獲所有路由或404路由

通過(guò)通配符 * 可匹配所有路徑,如需匹配404則應(yīng)將該路由配置在最后(先配置的路由匹配優(yōu)先級(jí)更高)

{
  path: '*'
}
history模式

利用了history.pushState API,使URL中將不再具有#。但需服務(wù)器端做好對(duì)應(yīng)配置。

const router = new VueRouter({
  mode: 'history',//默認(rèn)為hash
  routes: [...]
})
重定向

重定向需要精準(zhǔn)匹配(如父子路由都配置了redirect,且此時(shí)跳向子路由,則只會(huì)觸發(fā)子的redirect)
導(dǎo)航守衛(wèi)只會(huì)對(duì)重定向之后的路由生效

  routes: [
    { path: '/a', redirect: '/bar' },
    { path: '/b', redirect: { name: 'foo' }}
  ]
別名

/a 的別名是 /b,意味著,當(dāng)用戶(hù)訪(fǎng)問(wèn) /b 時(shí),URL 會(huì)保持為 /b,但是路由匹配則為 /a,就像用戶(hù)訪(fǎng)問(wèn) /a 一樣。

{ path: '/a', component: A, alias: '/b' }

導(dǎo)航和出口

<router-link> 默認(rèn)會(huì)被渲染成一個(gè) <a> 標(biāo)簽,將匹配到的組件渲染在路由出口<router-view>
以 / 開(kāi)頭的嵌套路徑會(huì)被當(dāng)作根路徑

<router-link to="/foo">Go to Foo</router-link>
<router-view></router-view>
編程式的導(dǎo)航
  1. router.push(location, onComplete?, onAbort?)
    location可以為對(duì)象或字符串。注意當(dāng)對(duì)象使用path時(shí),params會(huì)被忽略。
    同樣的規(guī)則也適用于 router-link 組件的 to 屬性。
// 字符串
router.push('home')
// 對(duì)象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
// 帶查詢(xún)參數(shù),變成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})

onCompleteonAbort回調(diào)將會(huì)在導(dǎo)航成功完成 (在所有的異步鉤子被解析之后) 或終止 (導(dǎo)航到相同的路由、或在當(dāng)前導(dǎo)航完成之前導(dǎo)航到另一個(gè)不同的路由) 的時(shí)候進(jìn)行相應(yīng)的調(diào)用

  1. router.replace(location, onComplete?, onAbort?)
    不會(huì)向 history 添加新記錄
  2. router.go(n)
    傳入-1時(shí)即為后退
命名出口

同一層級(jí)下存在多個(gè)視圖,可通過(guò)name區(qū)分,默認(rèn)為default

<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>

const router = new VueRouter({
  routes: [
    {
      path: '/',
      components: {
        default: Foo,
        a: Bar,
        b: Baz
      }
    }
  ]
})

導(dǎo)航守衛(wèi)

觸發(fā)條件

路由參數(shù)(如:id)或查詢(xún)(query)的改變會(huì)復(fù)用組件,并不會(huì)觸發(fā)進(jìn)入/離開(kāi)的導(dǎo)航守衛(wèi),也不會(huì)銷(xiāo)毀/創(chuàng)建目標(biāo)組件。因此組件的生命周期也不會(huì)觸發(fā)。此時(shí)可以通過(guò)以下方式相應(yīng)路由參數(shù)變化:

  1. watch $route 對(duì)象
  2. 組件內(nèi)導(dǎo)航守衛(wèi)beforeRouteUpdate (to, from, next) {}
觸發(fā)順序

導(dǎo)航被觸發(fā)。
在失活的組件里調(diào)用離開(kāi)守衛(wèi)。beforeRouteLeave
如此時(shí)發(fā)生redirect,以下內(nèi)容只會(huì)對(duì)redirect后的路由生效
進(jìn)入路由時(shí)如果為嵌套路由,則總是先觸發(fā)父組件的相應(yīng)守衛(wèi)
調(diào)用全局的 beforeEach 守衛(wèi)。
在重用的組件里調(diào)用 beforeRouteUpdate 守衛(wèi) (2.2+)。
在路由配置里調(diào)用 beforeEnter。
解析異步路由組件。
在被激活的組件里調(diào)用 beforeRouteEnter。
調(diào)用全局的 beforeResolve 守衛(wèi) (2.5+)。
導(dǎo)航被確認(rèn)。
調(diào)用全局的 afterEach 鉤子。
觸發(fā) DOM 更新。
用創(chuàng)建好的實(shí)例調(diào)用 beforeRouteEnter 守衛(wèi)中傳給 next 的回調(diào)函數(shù)。

全局前置守衛(wèi) router.beforeEach
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
  // ...
})

當(dāng)一個(gè)導(dǎo)航觸發(fā)時(shí),全局前置守衛(wèi)按照創(chuàng)建順序調(diào)用。守衛(wèi)是異步解析執(zhí)行,此時(shí)導(dǎo)航在所有守衛(wèi) resolve 完之前一直處于 等待中。
每個(gè)守衛(wèi)方法接收三個(gè)參數(shù):

  • to: Route: 即將要進(jìn)入的目標(biāo)路由
  • from: Route: 當(dāng)前導(dǎo)航正要離開(kāi)的路由
  • next: Function: 一定要調(diào)用該方法來(lái) resolve 這個(gè)鉤子。執(zhí)行效果依賴(lài) next 方法的調(diào)用參數(shù)。
    • next(): 進(jìn)行管道中的下一個(gè)鉤子。如果全部鉤子執(zhí)行完了,則導(dǎo)航的狀態(tài)就是 confirmed (確認(rèn)的)。

    • next(false): 中斷當(dāng)前的導(dǎo)航。如果瀏覽器的 URL 改變了 (可能是用戶(hù)手動(dòng)或者瀏覽器后退按鈕),那么 URL 地址會(huì)重置到 from 路由對(duì)應(yīng)的地址。

    • next('/') 或者 next({ path: '/' }): 跳轉(zhuǎn)到一個(gè)不同的地址。當(dāng)前的導(dǎo)航被中斷,然后進(jìn)行一個(gè)新的導(dǎo)航。你可以向 next 傳遞任意位置對(duì)象,且允許設(shè)置諸如 replace: truename: 'home' 之類(lèi)的選項(xiàng)以及任何用在 router-linkto proprouter.push 中的選項(xiàng)。

    • next(error): (2.4.0+) 如果傳入 next 的參數(shù)是一個(gè) Error 實(shí)例,則導(dǎo)航會(huì)被終止且該錯(cuò)誤會(huì)被傳遞給 router.onError() 注冊(cè)過(guò)的回調(diào)。
      確保要調(diào)用 next 方法,否則鉤子就不會(huì)被 resolved。

全局解析守衛(wèi) router.beforeResolve

router.beforeEach 類(lèi)似,區(qū)別是在導(dǎo)航被確認(rèn)之前,同時(shí)在所有組件內(nèi)守衛(wèi)和異步路由組件被解析之后,解析守衛(wèi)就被調(diào)用。

全局后置鉤子 afterEach

不會(huì)接受 next 函數(shù)也不會(huì)改變導(dǎo)航本身

router.afterEach((to, from) => {
  // ...
})
路由獨(dú)享的守衛(wèi) beforeEnter
const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})
組件內(nèi)守衛(wèi)
  • beforeRouteEnter
  • beforeRouteUpdate
  • beforeRouteLeave
const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // 在渲染該組件的對(duì)應(yīng)路由被 confirm 前調(diào)用
    // 不!能!獲取組件實(shí)例 `this`,因?yàn)楫?dāng)守衛(wèi)執(zhí)行前,組件實(shí)例還沒(méi)被創(chuàng)建
    next(vm => {
      // 但是可以通過(guò)回調(diào)中的 `vm` 訪(fǎng)問(wèn)組件實(shí)例
    })
  },
  beforeRouteUpdate (to, from, next) {
    // 在當(dāng)前路由改變,但是該組件被復(fù)用時(shí)調(diào)用
    // 舉例來(lái)說(shuō),對(duì)于一個(gè)帶有動(dòng)態(tài)參數(shù)的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉(zhuǎn)的時(shí)候,
    // 由于會(huì)渲染同樣的 Foo 組件,因此組件實(shí)例會(huì)被復(fù)用。而這個(gè)鉤子就會(huì)在這個(gè)情況下被調(diào)用。
    // 可以訪(fǎng)問(wèn)組件實(shí)例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 導(dǎo)航離開(kāi)該組件的對(duì)應(yīng)路由時(shí)調(diào)用
    // 可以訪(fǎng)問(wèn)組件實(shí)例 `this`
  }
}

路由元信息 meta

可用于存儲(chǔ)該路由的一些自定義信息,如權(quán)限檢測(cè)、是否需要登錄等。
一個(gè)路由匹配到的所有路由記錄(包括所有祖先)會(huì)暴露為 $route.matched 數(shù)組。我們可以遍歷 $route.matched 來(lái)檢查路由記錄中的 meta 字段。

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      children: [
        {
          path: 'bar',
          component: Bar,
          meta: { requiresAuth: true }
        }
      ]
    }
  ]
})

router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth)) {
    if (!auth.loggedIn()) {
      next({
        path: '/login',
        query: { redirect: to.fullPath }
      })
    } else {
      next()
    }
  } else {
    next() // 確保一定要調(diào)用 next()
  }
})

滾動(dòng)行為

查看文檔

換到新路由時(shí),想要頁(yè)面滾到指定位置,或者是保持原先的滾動(dòng)位置,或滾動(dòng)到目標(biāo)錨點(diǎn)。

const router = new VueRouter({
  routes: [...],
  scrollBehavior (to, from, savedPosition) {
    // return 期望滾動(dòng)到哪個(gè)的位置
    // `savedPosition` 當(dāng)且僅當(dāng) popstate 導(dǎo)航 (通過(guò)瀏覽器的 前進(jìn)/后退 按鈕觸發(fā)) 時(shí)才可用。
  }
})

路由懶加載

把不同路由對(duì)應(yīng)的組件分割成不同的代碼塊,當(dāng)路由被訪(fǎng)問(wèn)的時(shí)候才加載對(duì)應(yīng)組件

Webpack自動(dòng)分割
const Foo = () => import('./Foo.vue')

const router = new VueRouter({
  routes: [
    { path: '/foo', component: Foo }
  ]
})
把組件按組分塊

通過(guò)命名chunk,一個(gè)特殊的注釋語(yǔ)法,Webpack 會(huì)將相同塊名稱(chēng)的異步模塊組合到相同的異步塊中。

const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容