Vue-5 路由參數的傳遞和獲取(query 和 params),導航守衛和路由元信息,History模式

Vue-5 路由傳參的幾種方式(query和params),獲取路由參數,導航守衛和路由元信息,History模式

除了 props$emit 之外,路由時也可以攜帶數據,即通過路由傳參。

一、路由參數的傳遞和接收

1. 動態路由的匹配

示例需求:有個商品詳情的組件,點擊任何商品都會渲染這個組件,點擊商品時向詳情組件傳遞商品的 id,詳情組件在被渲染時接收這個 id,請求對應的數據,渲染在詳情組件上。

可以在配置路由時直接爲參數預留路徑:

// router>index.js 的routes
routes: [
    {
        // 在路徑中預留參數的位置
        path: '/good-detail/:id',
        component: Detail
    }
]

調用:

<!-- 調用路由時向路由傳參 -->
<router-link to="/good-detail/1">商品1</router-link>
<router-link to="/good-detail/2">商品2</router-link>
<router-link to="/good-detail/3">商品3</router-link>

<!-- 渲染詳情組件 -->
<router-view />

接收參數:

<!-- 詳情組件的結構中接收 -->
<div class="detail">
    <!-- 用 $route 獲取路由信息,從路由信息的 params 中接收參數  -->
    {{ this.$route.params.id }}
</div>
// 如果想要在組件剛開始加載時獲取 id,並且根據 id 做一些數據操作,那就在對應的鉤子函數中,獲取路由參數
created() { // detail 組件生命週期的 created 鉤子函數
    const id = this.$route.params.id;
    // code
}

createdmounted 函數,只能在第一個商品被渲染時響應,detail 組件在第一次被渲染之後,雖然路由變了,但是 createdmounted 不會重新執行。這種情況下,可以用 updated 來動態獲取路由參數。也可以用 watch 來監聽路由的變化。

watch: {
    // to 和 from 分別表示路由切換前後的路由元信息
    '$route'(to, from) {
      // 對路由變化作出響應...
    }
}

2. router-link 的 to屬性傳參

如果使用 <router-link> 標籤的 to 屬性動態傳參,那麼路由配置時不需要在 path 路徑中預留參數的位置,直接傳參並接收就可以了。

// router>index.js 的routes
routes: [
    {
        // 路徑中不需要預留參數的位置
        path: '/good-detail',
        component: Detail
    }
]

傳參:

<!-- 
    to 動態傳參時,要傳一個對象,要綁定 v-bind 指令
    路由中的參數有兩個列表,分別是 query 和 params
-->
<router-link 
    :to="{
        path: '/good-detail',
        query: {
            id: 1
        }
    }"
>商品3</router-link>

接收參數:

// detail 組件的 created 鉤子函數
created() {
    const id = this.$route.query.id;
    // code
}

這樣傳參,有個好處,就是有多個參數時,無論是配置還是傳參,代碼都非常簡潔,如果有多個參數,直接列在 query 對象中就可以了。

但是也有個缺點,就是傳遞的參數會暴露在 url 中,如果參數中的信息是需要保護的信息,那麼直接暴露就沒有任何安全性了。

這就要用到 paramsparamsquery 的區別就是 params 中的參數不會暴露在 url 中,query 會。

但是 params 需要和路由的 name 結合使用。

// router>index.js 的routes
routes: [
    {
        path: '/good-detail',
        name: 'good-detail',
        component: Detail
    }
]
<router-link 
    :to="{
        name: 'good-detail',
        params: {
            id: 1
        }
    }"
>商品3</router-link>

獲取 params 中的參數:

// detail 組件的 created 鉤子函數
created() {
    const id = this.$route.params.id;
    // code
}

注:
path 只能和 query 結合使用,name 可以和 query 或者 params 結合使用,但是 namequery 結合使用時,參數依舊會暴露。

3. push 時傳參

// path 和 query 結合使用
this.$router.push({
    path: '/good-detail',
    query: {
        id: 1
    }
});

// name 和 query 結合使用
this.$router.push({
    name: 'good-detail',
    query: {
        id: 1
    }
});

// name 和 params 結合使用
this.$router.push({
    path: '/good-detail',
    params: {
        id: 1
    }
});

接受參數方式不變。

二、導航守衛和路由元信息

1. 導航守衛

通俗點說,導航守衛指在路由切換時,對組件中的數據或者用戶信息做一些保護和判斷。

比如用戶從 A 組件切換到 B 組件,但是 B 組件中的內容是要根據用戶的權限渲染的,不同權限的用戶渲染不同的內容。就需要在切換之前拿到用戶的權限信息,做判斷之後再切換組件。

還有一種可能性,某個後臺管理系統只能在用戶登錄之後才展示相對應的頁面,但是用戶可能已經知道了首頁的路徑,用戶可能沒經過登錄直接在瀏覽器輸入首頁路徑,要強行進入首頁,那麼在此之前,我們要做導航守衛。

其實我們可以把導航守衛理解成路由過程中的鉤子函數。

全局守衛

// router>index.js
import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

const router =  new Router({
  routes: [
      // ...
  ]
});

// 全局前置守衛
router.beforeEach((to, from, next) => {
    // code
});

// 全局後置鉤子
router.afterEach((to, from) => {
  // ...
});

export default router

全局的守衛會在每個路由發生變化時響應,但是有時候我們只需要在某個路由發生變化時做一些操作,並不需要所有路由全部響應切換。全局守衛的循環還是稍微有點耗性能。

某個路由自己的守衛

import Vue from 'vue'
import Router from 'vue-router'

import GoodDetail from '@/components/GoodDetail'

Vue.use(Router)

export default new Router({
    routes: [
        {
            path: '/good-detail',
            component: GoodDetail,
            beforeEnter: (to, from, next) => {
                // 只有當前路由切換時要響應的代碼
                // 和其他路由沒有任何關係
            }
        }
    ]
})

如果需要在某個組件中,捕獲到路由變化之後或者之前,對數據做一些保留或清除動作。

比如從商品列表切換到商品詳情,我們可以在詳情組件路由切換成功的鉤子函數中,獲取路由參數,就可以使用組件中的路由守衛(當然也可以用組件生命週期鉤子函數,也可以使用watch,這裏組件中的路由守衛只是提供另一種可能性)。

組件內的守衛

// 某個組件的 export 
export default {
    name: 'Detail',
    // vue-router 文檔提供的示例
    beforeRouteEnter (to, from, next) {
        // 在渲染該組件的對應路由被 confirm 前調用
        // 不!能!獲取組件實例 `this`
        // 因爲當守衛執行前,組件實例還沒被創建
    },
    beforeRouteUpdate (to, from, next) {
        // 在當前路由改變,但是該組件被複用時調用
        // 舉例來說,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
        // 由於會渲染同樣的 Foo 組件,因此組件實例會被複用。而這個鉤子就會在這個情況下被調用。
        // 可以訪問組件實例 `this`
    },
    beforeRouteLeave (to, from, next) {
        // 導航離開該組件的對應路由時調用
        // 可以訪問組件實例 `this`
    }
}

注:
beforeRouteEnter 守衛 不能 訪問 this,因爲守衛在導航確認前被調用,因此即將登場的新組件還沒被創建。

完整的導航流程解析

官網給了導航切換的整個細緻流程及每個階段的鉤子函數。

  • 導航被觸發。
  • 在失活的組件裏調用離開守衛。
  • 調用全局的 beforeEach 守衛。
  • 在重用的組件裏調用 beforeRouteUpdate 守衛 (2.2+)。
  • 在路由配置裏調用 beforeEnter。
  • 解析異步路由組件。
  • 在被激活的組件裏調用 beforeRouteEnter。
  • 調用全局的 beforeResolve 守衛 (2.5+)。
  • 導航被確認。
  • 調用全局的 afterEach 鉤子。
  • 觸發 DOM 更新。
  • 用創建好的實例調用 beforeRouteEnter 守衛中傳給 next 的回調函數。

to, from, next

在上面的很多例子中,我們都能看到 鉤子函數接收的參數,to,from,next。它們都代表特殊的意義和作用。

  • to: Route: 即將要進入的目標 路由對象

  • from: Route: 當前導航正要離開的路由

  • next: Function: 一定要調用該方法來 resolve 這個鉤子。執行效果依賴 next 方法的調用參數。

    • next(): 進行管道中的下一個鉤子。如果全部鉤子執行完了,則導航的狀態就是 confirmed (確認的)。

    • next(false): 中斷當前的導航。如果瀏覽器的 URL 改變了 (可能是用戶手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到 from 路由對應的地址。

    • next(’/’) 或者 next({ path: ‘/’ }): 跳轉到一個不同的地址。當前的導航被中斷,然後進行一個新的導航。你可以向 next 傳遞任意位置對象,且允許設置諸如 replace: true、name: ‘home’ 之類的選項以及任何用在 router-link 的 to prop 或 router.push 中的選項。

    • next(error): (2.4.0+) 如果傳入 next 的參數是一個 Error 實例,則導航會被終止且該錯誤會被傳遞給 router.onError() 註冊過的回調。

2. 路由元信息

在配置路由時,路由對應的某些固定數據,我們可以直接綁定在路由配置對象的 meta 對象中,然後在需要時獲取。

// router>index.js 的 routes
routes: [
    {
        path: '/good-detail',
        component: GoodDetail,
        // 定義路由的時候可以配置 meta 字段:
        meta: {
            title: '商品詳情',
            ifSee: true
        }
    }
]

獲取路由元信息:

// Detail 組件的 created
created() {
    console.log(this.$route.meta);
}

History 模式

我們在運行項目時,能看到 url 中帶有一個 # ,這個是 vue-router 默認的 hash 模式。因爲正常情況下,切換瀏覽器的 url 瀏覽器中的內容是要刷新的,但是我們希望的是通過在 url 中切換路由來實現頁面組件的切換,所以 vue-routerurl 中添加了 # 號,這樣在切換路由導致 url 改變時不會刷新頁面。其實 <router-link> 標籤最終渲染的真實 DOM<a>to 屬性是 <a> 標籤的 href# 是錨點:

<a data-v-957c9522="" href="#/good-detail" class="router-link-exact-active router-link-active">詳情</a>

如果不想要很醜的 hash,我們可以用路由的 history 模式,這種模式充分利用 history.pushState API 來完成 URL 跳轉而無須重新加載頁面。

const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

當使用 history 模式時,URL 就像正常的 url,例如 http://yoursite.com/user/id。

只是設置成 history 之後,一些與後臺的數據交互需要依賴後臺配置。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章