[Vue 牛刀小試]:第十四章 - 編程式導航與實現組件與 Vue Router 之間的解耦

 1、前言

  在上一章的學習中,經過舉例說明,咱們瞭解了 Vue Router 中命名路由、命名視圖的使用方法,以及如何經過 query 查詢參數傳參,或者是採用 param 傳參的方式實現路由間的參數傳遞。經過學習咱們能夠發現,在實現路由間的參數傳遞時,咱們將 Vue Router 與咱們的組件強耦合在一塊兒,這無疑是不合適的,那麼本章咱們就來學習,如何實現組件和 Vue Router 之間的解耦。html

  學習系列目錄地址:http://www.javashuo.com/article/p-bzzucmub-ba.html前端

  倉儲地址:https://github.com/Lanesra712/VueTrial/blob/master/chapter02-bronze/router/decoupling.htmlvue

 2、乾貨合集

  一、編程式導航

  在使用 Vue Router 的時候,咱們一般會經過 router-link 標籤去生成跳轉到指定路由的連接,可是在實際的前端開發中,咱們更多的是經過 js 的方式進行跳轉。就像咱們很常見的一個交互需求,用戶提交表單,提交成功後跳轉到上一頁面,提交失敗則留在當前頁。這時候若是咱們仍是經過 router-link 標籤進行跳轉就不合適了,咱們須要經過 js 根據表單返回的狀態進行動態的判斷。git

  在使用 Vue Router 時,咱們已經將 Vue Router 的實例掛載到了 Vue 實例上,所以咱們就能夠藉助 $router 的實例方法,經過編寫 js 代碼的方式實現路由間的跳轉,而這種方式就是一種編程式的路由導航。github

  在 Vue Router 中具備三種導航方法,分別爲 push、replace 和 go。咱們最多見的經過在頁面上設置 router-link 標籤進行路由地址間的跳轉,就等同於執行了一次 push 方法。vue-router

  在這一小節的示例中,我將使用編程式導航實現經過點擊不一樣的按鈕實現路由間的跳轉,最終實現的示意圖以下所示。編程

  在以前學習 Vue Router 的基礎使用方法時,咱們瞭解到,前端路由的實現方式,實際上就是對於瀏覽器的 history api 的操做。瀏覽器的 history 對象提供了對瀏覽器的會話歷史的訪問,它暴露了不少有用的方法和屬性,容許咱們在用戶瀏覽歷史中向前和向後跳轉,同時從 HTML5 開始提供了對 history 棧中內容的操做。api

  而 Vue Router 所提供的 push、replace 和 go 方法則徹底能夠對應到瀏覽器 history api 中所提供的 history.pushState、history.replaceState 和 history.go 方法。瀏覽器

  1.一、pushapp

  當咱們須要跳轉新頁面時,咱們就能夠經過 push 方法將一條新的路由記錄添加到瀏覽器的 history 棧中,經過 history 的自身特性,從而驅使瀏覽器進行頁面的跳轉。同時,由於在 history 會話歷史中會一直保留着這個路由信息,因此當咱們後退時仍是能夠退回到當前的頁面。

  在 push 方法中,參數能夠是一個字符串路徑,或者是一個描述地址的對象,這裏其實就等同於咱們調用了 history.pushState 方法。

// 字符串 => /first
this.$router.push('first')

// 對象 => /first
this.$router.push({ path: 'first' })

// 帶查詢參數 => /first?abc=123
this.$router.push({ path: 'first', query: { abc: '123' }})

  這裏須要注意,當咱們傳遞的參數爲一個對象而且當 path 與 params 共同使用時,對象中的 params 屬性不會起任何的做用,咱們須要採用命名路由的方式進行跳轉,或者是直接使用帶有參數的全路徑。

const userId = '123'

// 使用命名路由 => /user/123
this.$router.push({ name: 'user', params: { userId }})

// 使用帶有參數的全路徑 => /user/123
this.$router.push({ path: `/user/${userId}` })

// 這裏的 params 不生效 => /user
this.$router.push({ path: '/user', params: { userId }}) 

  1.二、go

  當咱們使用 go 方法時,咱們就能夠在 history 記錄中向前或者後退多少步,也就是說經過 go 方法你能夠在已經存儲的 history 路由歷史中來回跳。

// 在瀏覽器記錄中前進一步,等同於 history.forward()
this.$router.go(1)

// 後退一步記錄,等同於 history.back()
this.$router.go(-1)

// 前進 3 步記錄
this.$router.go(3)

// 若是 history 記錄不夠用,那就默默地失敗唄
this.$router.go(-100)
this.$router.go(100)

  1.三、replace

  replace 方法一樣能夠達到實現路由跳轉的目的,不過,從名字中你也能夠看出,與使用 push 方法跳轉不一樣是,當咱們使用 replace 方法時,並不會往 history 棧中新增一條新的記錄,而是會替換掉當前的記錄,所以,你沒法經過後退按鈕再回到被替換前的頁面。

this.$router.replace({
    path: '/special'
})

  經過編程式路由實現路由間切換的示例代碼以下所示,你能夠本身嘗試一下,去熟悉如何經過 js 來實現路由地址間的切換。

<div id="app">
    <div class="main">
        <div class="btn-toolbar" role="toolbar" aria-label="Toolbar with button groups">
            <div class="btn-group mr-2" role="group" aria-label="First group">
                <button type="button" class="btn btn-secondary" @click="goFirst">第一頁</button>
                <button type="button" class="btn btn-secondary" @click="goSecond">第二頁</button>
                <button type="button" class="btn btn-secondary" @click="goThird">第三頁</button>
                <button type="button" class="btn btn-secondary" @click="goFourth">第四頁</button>
            </div>
            <div class="btn-group mr-2" role="group" aria-label="Second group">
                <button type="button" class="btn btn-secondary" @click="pre">後退</button>
                <button type="button" class="btn btn-secondary" @click="next">前進</button>
            </div>
            <div class="btn-group mr-2" role="group" aria-label="Third group">
                <button type="button" class="btn btn-secondary" @click="replace">替換當前頁爲特殊頁</button>
            </div>
        </div>

        <router-view></router-view>
    </div>
</div>

<script>
    const first = {
        template: '<h3>當前是第一頁</h3>'
    }

    const second = {
        template: '<h3>當前是第二頁</h3>'
    }

    const third = {
        template: '<h3>當前是第三頁</h3>'
    }

    const fourth = {
        template: '<h3>當前是第四頁</h3>'
    }

    const special = {
        template: '<h3>特殊頁面</h3>'
    }


    const router = new VueRouter({
        routes: [{
            path: '/first',
            component: first
        }, {
            path: '/second',
            component: second
        }, {
            path: '/third',
            component: third
        }, {
            path: '/fourth',
            component: fourth
        }, {
            path: '/special',
            component: special
        }]
    })

    const vm = new Vue({
        el: '#app',
        data: {},
        methods: {
            goFirst() {
                this.$router.push({
                    path: '/first'
                })
            },
            goSecond() {
                this.$router.push({
                    path: '/second'
                })
            },
            goThird() {
                this.$router.push({
                    path: '/third'
                })
            },
            goFourth() {
                this.$router.push({
                    path: '/fourth'
                })
            },
            next() {
                this.$router.go(1)
            },
            pre() {
                this.$router.go(-1)
            },
            replace() {
                this.$router.replace({
                    path: '/special'
                })
            }
        },
        router: router
    })
</script>

  二、解耦

   在文章開頭咱們有提到過,在使用路由傳參的時候,咱們將組件與 Vue Router 強綁定在了一塊,這意味着在任何須要獲取路由參數的地方,咱們都須要加載 Vue Router。那麼,如何解決這一強綁定呢?

  在以前學習組件相關的知識時,咱們提到了能夠經過組件的 props 選項來實現子組件接收父組件傳遞的值。而在 Vue Router 中,一樣給咱們提供了經過使用組件的 props 選項來進行解耦的功能。

  在下面的示例中,在定義路由模板時,咱們經過指定須要傳遞的參數爲 props 選項中的一個數據項,以後,咱們經過在定義路由規則時,指定 props 屬性爲 true,便可實現對於組件以及 Vue Router 之間的解耦。

<script>
    const second = {
        props: ['id'],
        template: '<h3>當前是第二頁 --- {{id}} </h3>'
    }

    const router = new VueRouter({
        routes: [{
            path: '/second/:id',
            component: second,
            props: true
        }]
    })

    const vm = new Vue({
        el: '#app',
        data: {},
        methods: {
            goSecond() {
                this.$router.push({
                    path: '/second'
                })
            }
        },
        router: router
    })
</script>

  能夠看到,這裏採用 param 傳參的方式進行參數傳遞,而在組件中咱們並無加載 Vue Router 實例,也完成了對於路由參數的獲取。須要注意的是,採用此方法,只能實現基於 param 方式進行傳參的解耦。

  針對定義路由規則時,指定 props 屬性爲 true 這一種狀況,在 Vue Router 中,咱們還能夠給路由規則的 props 屬性定義成一個對象或是函數。不過,若是定義成對象或是函數,此時並不能實現對於組件以及 Vue Router 間的解耦。

  在將路由規則的 props 定義成對象後,此時無論路由參數中傳遞是任何值,最終獲取到的都是對象中的值。同時,須要注意的是,props 中的屬性值必須是靜態的,也就是說,你不能採用相似於子組件同步獲取父組件傳遞的值做爲 props 中的屬性值。

<script>
    const third = {
        props: ['name'],
        template: '<h3>當前是第三頁 --- {{name}} </h3>'
    }

    const router = new VueRouter({
        routes: [{
            path: '/third/:name',
            component: third,
            props: {
                name: 'zhangsan'
            }
        }]
    })

    const vm = new Vue({
        el: '#app',
        data: {},
        methods: {
            goThird() {
                this.$router.push({
                    path: '/third'
                })
            }
        },
        router: router
    })
</script>

  在對象模式中,咱們只能接收靜態的 props 屬性值,而當咱們使用函數模式以後,就能夠對靜態值作數據的進一步加工或者是與路由傳參的值進行結合。

<script>
    const fourth = {
        props: ['id', 'name'],
        template: '<h3>當前是第四頁 --- {{id}}  --- {{name}} </h3>'
    }

    const router = new VueRouter({
        routes: [{
            path: '/fourth',
            component: fourth,
            props: (route) => ({
                id: route.query.id,
                name: 'zhangsan'
            })
        }]
    })

    const vm = new Vue({
        el: '#app',
        data: {},
        methods: {
            goFourth() {
                this.$router.push({
                    path: '/fourth'
                })
            }
        },
        router: router
    })
</script>

 3、總結

  這一章主要學習瞭如何經過使用 Vue Router 的實例方法,從而實現編程式導航,以及如何實現組件與 Vue Router 之間的解耦。至此,Vue Router 的一些基礎使用方法也就大概介紹完了,其它的知識點將在後面的項目中具體使用到的時候再進行介紹,歡迎持續關注哈~~~

 4、參考

  一、History API與瀏覽器歷史堆棧管理

  二、可能比文檔還詳細--VueRouter徹底指北

  三、十全大補vue-router

相關文章
相關標籤/搜索