vue-router文檔細讀

Vue-Router

在組件內,可以通過 this.routerthis. route 訪問當前路由

當 對應的路由匹配成功,將自動設置 class 屬性值 .router-link-active

1. 動態路由匹配

通過設置路由的 path 爲 /user/:id 的這種形式,此時可以通過在組件內使用 this.$router.params.id 來進行接收參數 id 。這裏設置多段路由路徑參數也是可行的 /user/:username/post/:post_id

像這種路由參數的變化,並不會引起組件的銷燬重新創建,而是被複用。這就意味着組件的生命週期鉤子函數不會被調用。想要監測,我們可以通過使用 watch 來進行。

watch: {
    '$route' (to, from) {
        ...do someting
    }
}

或者使用導航守衛

beforeRouteUpdate (to, from, next) {
    ... do someting
}

關於匹配的優先級,同一個路徑可以匹配多個路由。優先級就按照路由定義的順序:誰先定義、誰的優先級就高

2. 嵌套路由

主要通過 VueRouter 的參數中使用 children 配置來進行嵌套

3. 編程式的導航

this.$router.push(location, onComplete, onAbort):導航到不同的 URL,這個方法會向 history 棧添加一個新的記錄,等同於 <router-link :to="...">

this.$router.push({naem: 'user', params: {userId: 123}})

// 帶上查詢參數,就必須使用 path,但是使用 path 會自動忽略 params
this.$router.push({path: 'user', query: {plan: 'a'}})

let userId = 123
this.$router.push({path: `/user/${userId}`})  // -> /user/123

router.replacerouter.push 中提供了 onCompleteonAbort 回調作爲第二個和第三個參數。這些回調會在導航成功完成(在所有的異步鉤子被解析之後),或終止(導航到相同的路由、或在當前導航完成之前導航到另一個不同的路由)的時候進行相應的調用

注意:如果目的地和當前路由相同,只有參數發生了變化(如從 /user/1 到 /user/2),這時候需要使用 beforeRouteUpdate 來響應這個變化

this.router.replace(location, onComplete, onAbort),和 router.push 相似,不過他不會向 history 添加新的記錄,而是替換掉當前的 history 記錄
聲明式:<router-link :to="..." replace>

this.$router.go(n) 參數是一個整數,代表在 history 記錄中向前或者向後退多少步,如果 history 記錄不夠用,則會默默的失敗

4. 命名路由

在創建路由實例的時候,通過在 routes 配置中給某個路由設置名稱:name: '...'

這時就可以通過:<router-link :to="{name: 'user', params: {userId: 123}}">,這個和使用 router.push() 是一回事

5. 命名視圖

顯示方式:

// 這裏沒有進行 name 命名的路由,是默認出口
<router-view></router-view>
<router-view name="a"></router-view>
<router-view name="b"></router-view>

在 router 實例中的創建:

routes: [
    {
        path: '/',
        components: {
            default: Foo,
            a: Bar,
            b: Laz
        }
    }
]

6. 重定向和別名

同樣可以通過 routes 配置來完成

routes: [
    { path: '/a', redirect: '/b' }
]

// 重定向的目標可以使一個命名的路由
routes: [
    { path: '/a', redirect: { name: 'foo' } }
]

// 設置可以使一個方法,動態返回重定向的目標
routes: [
    { path: '/a', redirect: to => {
        // 方法接受 目標路由 作爲參數
        // return 重定向的 字符串路徑 / 路徑對象
    } }
]

別名:

// 訪問 /b 是,URL會保持爲 /b,但是路由匹配爲 /a
routes: [
    routes: [
        { path: '/a', component: A, alias: '/b' }
    ]
]

7. 路由組件傳參

使用 props 將組件和路由解耦,取代與 $route 的耦合
“`
routes: [
{
path: ‘/user/:id’
component: User,
props: true
}
]

// 之後在 User 組件內,可以通過設置 props 來進行接收
const User = {
props: [‘id’],
template: <div>{{ id }}</div>
}


// 對於包含命名視圖的路由,必須要分別爲每個命名視圖添加 props 選項
routes: [
{
path: ‘/user/:id’,
components: {
default: User,
sidebar: Sidebar
},
props: {
default: true,
sidebar: false
}
}
]
“`

使用 props 的好處:可以在任何地方使用該組件,使得組件更易於重用和測試

props 被設置成相應的數據類型
1. 布爾模式:props 設置爲 true,route.params 將會被設置爲組件屬性
2. 對象模式:會被按原樣設置爲組件屬性,當 props 是靜態的時候有用
3. 函數模式:可以創建一個函數返回 props。這樣可以將參數轉換成另一種類型,將靜態值與基於路由的值結合等等

儘可能保持 props 函數爲無狀態的,因爲它只會在路由繁盛變化時起作用,如果需要狀態來定義 props。則使用包裝組件,這樣 Vue 纔可以對狀態變化做出反應

進階

1. 導航守衛

主要通過跳轉或取消的方式守衛導航,有多種機會植入路由導航過程中:全局的,單個路由獨享的,或者組件級的

注意:參數或者查詢的改變並不會觸發進入 / 離開的導航守衛,可以通過觀察 $route 對象來應對這些變化,或使用 beforeRouteUpdate 的組件內守衛

全局守衛

可以使用 router.beforeEach 註冊一個全局前置守衛

const router = new VueRouter({...})
router.beforeEach((to, from, next) => {
    // ...
})

當一個導航觸發時,全局前置守衛按照創建順序調用。守衛是異步解析執行的,此時導航在所有守衛 resolve 完之前一直處於等待中
每個守衛方法接受三個參數:
- to:即將要進入的目標路由對象
- from:當前導航正要離開的路由
- next:一定要調用這個方法來 resolve 這個鉤子。執行效果依賴 next 方法的調用參數

關於 next:
- next():進入下一個鉤子,如果全部鉤子執行完了,則導航的狀態是 comfirmed (確認的)
- next(false):中斷當前的導航,如果瀏覽器的 URL 改變了(可能是用戶手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到 from 路由對應的地址
- next(‘/’) 或者 next( {path: ‘/’ }):跳轉到一個不同的地址。當前的導航被中斷,然後進行新的導航
- next(error):如果參數是一個 Error 實例,則導航會終止且該錯誤會被傳遞給 router.onError() 註冊過的回調

注意:一定要確保調用 next 方法,否則鉤子就不會被 resolved

全局解析守衛

可以使用 router.beforeResolve 註冊一個全局守衛。這和 router.beforeEach 類似。區別是在導航被確認之前,同時在所有組件內守衛和異步路由組件被解析之後,解析守衛就被調用

全局後置鉤子

這個鉤子並不會改變導航本身,也不接收 next 函數

router.afterEach((to, from) => {
    // ...
})

路由獨享的守衛

可以直接在路由配置上定義 beforeEnter 守衛

routes: [
    {
        path: '/foo',
        component: Foo,
        beforeEnter: (to, from, next) => {
            // ...
        }
    }
]

組件內的守衛

  • beforeRouteEnter(to, from, next):渲染該組件的對應路由被 confirm 前調用,無法獲取 this,且組件的實例還沒有創建
  • beforeRouteUpdate(to, from, next):當前路由改變,但是該組件被複用時調用,可以訪問 this
  • beforeRouteLeave(to, from, next):導航離開該組件時調用,可以訪問 this

beforeRouteEnter 雖然不能訪問 this,但是可以通過 next 來訪問組件實例。在導航被確認的時候執行回調,並且把組件實例作爲回調方法的參數

beforeRouteEnter (to, from, next) {
    next (vm => {
        // 通過 vm 訪問組件實例
    })
}

注意:beforeRouteEnter 是支持給 next 傳遞迴調的唯一守衛。對於 beforeRouteUptate 和 beforeRouteLeave 來說,this 已經可用,所以不支持傳遞迴調,沒有必要

至於離開守衛 beforeRouteLeave 通常用來禁止用戶在還未保存前提前離開。該導航可以通過 next(false) 來取消

完整的導航解析流程
1. 導航被觸發
2. 在失活的組件裏調用離開守衛
3. 調用全局的 beforeEnter 守衛
4. 在重用的組件裏調用 beforeRouteUpdate 守衛
5. 在路由配置裏調用 beforeEnter
6. 解析異步路由組件
7. 在被激活的組件裏調用 beforeRouteEnter
8. 調用全局的 beforeResolve 守衛
9. 導航被確認
10. 調用全局的 afterEach 鉤子
11. 觸發 DOM 更新
12. 用創建好的實例調用 beforeRouteEnter 守衛中傳給 next 的回調函數

2. 路由元信息

定義路由時可以配置 meta 字段:

routes: [
    {
        path: '/foo',
        component: Foo,
        chilren: [
            {
                path: 'bar',
                component: Bar,
                meta: { requiresAuth: true }
            }
        ]
    }
]

routes 配置中的每個路由對象爲‘路由記錄’,路由記錄是可以嵌套的。因此當一個路由匹配成功時,他可能匹配了多個路由記錄
/foo/bar 這個 URL 會匹配父路由記錄和子路由記錄
一個路由匹配到的所有路由記錄會暴露爲 route route.matched 數組。因此我們需要遍歷 $route,matched 來檢查路由記錄中的 meta 字段

3. 過渡動效

<router-view>是基本的動態組件,所以我們可以用 transition> 件給他添加一些過渡效果

<transition>
    <router-view></router-view>
</transition>

單個路由的過渡

如果想讓每個路由組件有各自的過渡效果,可以在各路由組件內使用 <transition> 並設置不同的 name

cosnt Foo = {
    template: `
        <transition name="slide">
            <div class="foo">...</div>
        </transition>
    `
}

基於路由的動態過渡

可以基於當前路由與目標路由的變化關係,動態設置過渡效果

<transition :name="transitionName">
    <router-view></router-view>
</transition>
// 在父組件內,通過 watch $route 決定使用哪種過渡
watch: {
    '$route' (to, from) {
        // do someting
        this.transitionName = isActice ? 'slide-right' : 'slide-left'
    }
}

4. 數據獲取

渲染頁面需要從服務器獲取用戶的數據,這裏主要可以通過兩種方式來實現
- 導航完成之後獲取:先完成導航,然後在接下來的組件生命週期鉤子中獲取數據。在數據獲取期間顯示“加載中”之類的指示
- 導航完成之前獲取:導航完成之前,在路由進入的守衛中獲取數據,在數據獲取成功後執行導航(獲取數據時,用戶會停留在當前的界面)

5. 滾動行爲

這個功能只在支持 history.pushState 的瀏覽器中可用
在 Router 實例中,提供了一個 scrollBehavior 方法

const router = new VueRouter({
    routes: [...],
    scrollBehavior (ro, from, savedPosition) {
        // return 期望滾動到哪個位置
    }
})

這裏的第三個參數 savedPosition 當且僅當 popstate 導航(通過瀏覽器的 前進 / 後退 按鈕觸發)時纔可用,具體展示:

{x: number, y: number}
{selector: string, offset? : {x: number, y: number}}
// 如果返回的是一個 falsy 的值,或者空對象,那麼不會發生滾動行爲
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章