[Vue 牛刀小試]:第十三章 - Vue Router 基礎使用再探(命名路由、命名視圖、路由傳參)

 1、前言

  在上一章的學習中,咱們簡單介紹了前端路由的概念,以及如何在 Vue 中經過使用 Vue Router 來實現咱們的前端路由。可是在實際使用中,咱們常常會遇到路由傳參、或者一個頁面是由多個組件組成的狀況。本章,咱們就來介紹下在這兩種狀況下 Vue Router 的使用方法以及一些可能涉及到的概念。html

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

  倉儲地址:https://github.com/Lanesra712/VueTrial/tree/master/chapter02-bronze/router/passvue

 2、乾貨合集

  一、命名路由

  在某些時候,咱們指望生成的路由 URL 地址可能會很長,在使用中可能會顯得有些不便。這時候經過一個名稱來標識一個路會更方便一些,所以在 Vue Router 中,咱們能夠在建立 Router 實例的時候,經過在 routes 配置中給某個路由設置名稱,從而方便的調用路由。git

const router = new VueRouter({
  routes: [
    {
      path: '/form',
      name: 'form',
      component: '<div>form 組件</div>'
    }
  ]
})

  當咱們使用命名路由以後,當須要使用 router-link 標籤進行跳轉時,就能夠採起給 router-link 的 to 屬性傳一個對象的方式,跳轉到指定的路由地址上。github

<router-link :to="{ name: 'form'}">User</router-link>

  二、命名視圖

  當咱們打開一個頁面時,整個頁面多是由多個 Vue 組件所構成的,例如,咱們的後臺管理首頁多是由 sidebar (側導航) 、header(頂部導航)和 main (主內容)這三個 Vue 組件構成的。此時,當咱們經過 Vue Router 構建路由信息時,若是一個 URL 只能對應一個 Vue 組件,整個頁面確定是沒法正確顯示的。面試

  在上一章的學習中,咱們在構建路由信息的時候有使用到兩個特殊的標籤:router-view 和 router-link。經過 router-view 標籤,咱們就能夠指定組件渲染顯示到什麼位置。所以,當咱們須要在一個頁面上顯示多個組件的時候,就須要在頁面中添加多個的 router-view 標籤。vue-router

  那麼,是否是能夠經過一個路由對應多個組件,而後按需渲染在不一樣的 router-view 標籤上呢?按照上一章中介紹的關於 Vue Router 的使用方法,咱們能夠很容易的實現下面的代碼。app

<div id="app">
    <router-view></router-view>
    <div class="container">
        <router-view></router-view>
        <router-view></router-view>
    </div>
</div>

<template id="sidebar">
    <div class="sidebar">
        sidebar
    </div>
</template>

<script>
    // 一、定義路由跳轉的組件模板
    const header = {
        template: '<div class="header"> header </div>'
    }

    const sidebar = {
        template: '#sidebar',
    }

    const main = {
        template: '<div class="main"> main </div>'
    }

    // 二、定義路由信息
    const routes = [{
        path: '/',
        component: header
    }, {
        path: '/',
        component: sidebar
    }, {
        path: '/',
        component: main
    }]

    const router = new VueRouter({
        routes
    })

    // 三、掛載到當前 Vue 實例上
    const vm = new Vue({
        el: '#app',
        data: {},
        methods: {},
        router: router
    });
</script>

  能夠看到,並無實現咱們想要實現的效果,當咱們將一個路由信息對應到多個組件時,無論有多少個的 router-view 標籤,程序都會將第一個組件渲染到全部的 router-view 標籤上。ide

  所以,在這種狀況下,咱們須要實現的是一個路由信息能夠按照咱們的須要去渲染到頁面中指定的 router-view 標籤上,而在 Vue Router 中,咱們則能夠經過命名視圖的方式實現咱們的需求。post

  命名視圖,從名稱上看可能沒法闡述的很清楚,與命名路由的實現方式類似,命名視圖經過在 router-view 標籤上設定 name 屬性,以後,在構建路由與組件的對應關係時,以一種 name:component 的形式構造出一個組件對象,從而指明是在哪一個 router-view 標籤上加載什麼組件。

  注意,這裏在指定路由對應的組件時,使用的是 components(包含 s)屬性進行配置組件。實現命名視圖的代碼以下所示。

<div id="app">
    <router-view></router-view>
    <div class="container">
        <router-view name="sidebar"></router-view>
        <router-view name="main"></router-view>
    </div>
</div>

<script>
    // 二、定義路由信息
    const routes = [{
        path: '/',
        components: {
            default: header,
            sidebar: sidebar,
            main: main
        }
    }]
</script>

  在 router-view 中,默認的 name 屬性值爲 default,因此這裏的 header 組件對應的 router-view 標籤就能夠不設定 name 屬性值。完整的示例代碼以下。

<div id="app">
    <router-view></router-view>
    <div class="container">
        <router-view name="sidebar"></router-view>
        <router-view name="main"></router-view>
    </div>
</div>

<template id="sidebar">
    <div class="sidebar">
        sidebar
    </div>
</template>

<script>
    // 一、定義路由跳轉的組件模板
    const header = {
        template: '<div class="header"> header </div>'
    }

    const sidebar = {
        template: '#sidebar'
    }

    const main = {
        template: '<div class="main"> main </div>'
    }

    // 二、定義路由信息
    const routes = [{
        path: '/',
        components: {
            default: header,
            sidebar: sidebar,
            main: main
        }
    }]

    const router = new VueRouter({
        routes
    })

    // 三、掛載到當前 Vue 實例上
    const vm = new Vue({
        el: '#app',
        data: {},
        methods: {},
        router: router
    });
</script>

  三、路由傳參

  在不少的狀況下,例如表單提交,組件跳轉之類的操做,咱們須要使用到上一個表單、組件的一些數據,這時咱們就須要將須要的參數經過參數傳參的方式在路由間進行傳遞。

  例如,在下面的示例中,咱們想要實現經過點擊 main 組件中的子組件 form 組件上的按鈕,將表單的內容傳遞到 info 子組件中進行顯示,功能示意圖以下所示。

  3.一、query 傳參

  query 查詢參數傳參,就是將咱們須要的參數以 key=value 的方式放在 url 地址中。例如這裏的需求,咱們須要在 info 組件中顯示上一個頁面的數據,因此咱們的 info 頁面顯示的 URL 地址應該爲 /info?email=xxx&password=xxx,這裏的 email 和 password 參數值則是 form 組件上用戶輸入的值。以後,咱們經過獲取這兩個參數值便可實現咱們的需求。

  當咱們將實例化的 VueRouter 對象掛載到 Vue 實例後,Vue Router 在咱們的 Vue 實例上建立了兩個屬性對象 this.$router(router 實例) 和 this.$route(當前頁面的路由信息)。從下圖能夠看到,咱們能夠經過 vm.$route 獲取到當前頁面的路由信息,而這裏的 query 對象則是咱們須要的。

  能夠看到,這時咱們就能夠直接經過 $route.query.參數名 的方式獲取到對應的參數值。同時能夠發現,fullPath 屬性能夠獲取到當前頁面的地址和 query 查詢參數,而 path 屬性則只是獲取到當前的路由信息。

  同時,由於在使用 Vue Router 時已經將 VueRouter 實例掛載到 Vue 實例上,所以就能夠直接經過調用 $router.push 方法來導航到另外一個頁面,因此這裏 form 組件中的按鈕事件,咱們就可使用這種方式完成路由地址的跳轉,完整的代碼以下。

<div id="app">
    <div class="row">
        <div class="col">
            <router-view></router-view>
        </div>
    </div>
    <div class="row">
        <div class="col-sm-2 sidebar">
            <router-view name="sidebar"></router-view>
        </div>
        <div class="col-sm-10 main">
            <router-view name="main"></router-view>
        </div>
    </div>
</div>

<template id="sidebar">
    <div>
        <ul>
            <router-link v-for="(item,index) in menu" :key="index" :to="item.url" tag="li">{{item.name}}
            </router-link>
        </ul>
    </div>
</template>

<template id="main">
    <div>
        <router-view> </router-view>
    </div>
</template>

<template id="form">
    <div>
        <form>
            <div class="form-group">
                <label for="exampleInputEmail1">Email address</label>
                <input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp"
                    placeholder="Enter email" v-model="email">
                <small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone
                    else.</small>
            </div>
            <div class="form-group">
                <label for="exampleInputPassword1">Password</label>
                <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password"
                    v-model="password">
            </div>
            <button type="submit" class="btn btn-primary" @click="submit">Submit</button>
        </form>
    </div>
</template>

<template id="info">
    <div class="card" style="margin-top: 5px;">
        <div class="card-header">
            輸入的信息
        </div>
        <div class="card-body">
            <blockquote class="blockquote mb-0">
                <p>Email Address:{{ $route.query.email }} </p>
                <p>Password:{{ $route.query.password }}</p>
                <footer class="blockquote-footer">Someone famous in <cite title="Source Title">Source Title</cite>
                </footer>
            </blockquote>
        </div>
    </div>
</template>

<script>
    // 一、定義路由跳轉的組件模板
    const header = {
        template: '<div class="header"> header </div>'
    }

    const sidebar = {
        template: '#sidebar',
        data() {
            return {
                menu: [{
                    name: 'Form',
                    url: '/form'
                }, {
                    name: 'Info',
                    url: '/info'
                }]
            }
        },
    }

    const main = {
        template: '#main'
    }

    const form = {
        template: '#form',
        data() {
            return {
                email: '',
                password: ''
            }
        },
        methods: {
            submit() {
                this.$router.push({
                    path: '/info?email=' + this.email + '&password=' + this.password
                })
            }
        },
    }

    const info = {
        template: '#info'
    }

    // 二、定義路由信息
    const routes = [{
        path: '/',
        components: {
            default: header,
            sidebar: sidebar,
            main: main
        },
        children: [{
            path: '',
            redirect: 'form'
        }, {
            path: 'form',
            component: form
        }, {
            path: 'info',
            component: info
        }]
    }]

    const router = new VueRouter({
        routes
    })

    // 三、掛載到當前 Vue 實例上
    const vm = new Vue({
        el: '#app',
        data: {},
        methods: {},
        router: router
    });
</script>

  3.二、param 傳參

  與獲取 query 參數的方式相同,咱們一樣能夠經過 vm.$route 獲取到當前路由信息,從而在 param 對象中經過 $route.params.參數名 的方式獲取到經過 param 的方式進行參數傳遞的值。

  不過,與 query 查詢參數傳參不一樣的是,在定義路由信息時,咱們須要以佔位符(:參數名)的方式將須要傳遞的參數指定到路由地址中,實現代碼以下。

const routes = [{
    path: '/',
    components: {
        default: header,
        sidebar: sidebar,
        main: main
    },
    children: [{
        path: '',
        redirect: 'form'
    }, {
        path: 'form',
        name: 'form',
        component: form
    }, {
        path: 'info/:email/:password',
        name: 'info',
        component: info
    }]
}]

  由於在使用 $route.push 進行路由跳轉時,若是提供了 path 屬性,則對象中的 params 屬性會被忽略,因此這裏咱們能夠採用命名路由的方式進行跳轉或者直接將參數值傳遞到路由 path 路徑中。同時,與使用 query 查詢參數傳遞參數不一樣,這裏的參數若是不進行賦值的話,就沒法與咱們的匹配規則對應,也就沒法跳轉到指定的路由地址中。

const form = {
    template: '#form',
    data() {
        return {
            email: '',
            password: ''
        }
    },
    methods: {
        submit() {
            // 方式1
            this.$router.push({
                name: 'info',
                params: {
                    email: this.email,
                    password: this.password
                }
            })

            // 方式2
            this.$router.push({
                path: `/info/${this.email}/${this.password}`,
            })
        }
    },
}

  其他的部分與使用 query 查詢參數傳參的方式相同,這裏我就直接給出實現代碼了,實現的示意圖以下。

<div id="app">
    <div class="row">
        <div class="col">
            <router-view></router-view>
        </div>
    </div>
    <div class="row">
        <div class="col-sm-2 sidebar">
            <router-view name="sidebar"></router-view>
        </div>
        <div class="col-sm-10 main">
            <router-view name="main"></router-view>
        </div>
    </div>
</div>

<template id="sidebar">
    <div>
        <ul>
            <router-link v-for="(item,index) in menu" :key="index" :to="{name:item.routeName}" tag="li">
                {{item.displayName}}
            </router-link>
        </ul>
    </div>
</template>

<template id="main">
    <div>
        <router-view> </router-view>
    </div>
</template>

<template id="form">
    <div>
        <form>
            <div class="form-group">
                <label for="exampleInputEmail1">Email address</label>
                <input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp"
                    placeholder="Enter email" v-model="email">
                <small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone
                    else.</small>
            </div>
            <div class="form-group">
                <label for="exampleInputPassword1">Password</label>
                <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password"
                    v-model="password">
            </div>
            <button type="submit" class="btn btn-primary" @click="submit">Submit</button>
        </form>
    </div>
</template>

<template id="info">
    <div class="card" style="margin-top: 5px;">
        <div class="card-header">
            輸入的信息
        </div>
        <div class="card-body">
            <blockquote class="blockquote mb-0">
                <p>Email Address:{{ $route.params.email }} </p>
                <p>Password:{{ $route.params.password }}</p>
                <footer class="blockquote-footer">Someone famous in <cite title="Source Title">Source Title</cite>
                </footer>
            </blockquote>
        </div>
    </div>
</template>

<script>
    // 一、定義路由跳轉的組件模板
    const header = {
        template: '<div class="header"> header </div>'
    }

    const sidebar = {
        template: '#sidebar',
        data() {
            return {
                menu: [{
                    displayName: 'Form',
                    routeName: 'form'
                }, {
                    displayName: 'Info',
                    routeName: 'info'
                }]
            }
        },
    }

    const main = {
        template: '#main'
    }

    const form = {
        template: '#form',
        data() {
            return {
                email: '',
                password: ''
            }
        },
        methods: {
            submit() {
                // 方式1
                this.$router.push({
                    name: 'info',
                    params: {
                        email: this.email,
                        password: this.password
                    }
                })

                // 方式2
                // this.$router.push({
                //     path: `/info/${this.email}/${this.password}`,
                // })
            }
        },
    }

    const info = {
        template: '#info'
    }

    // 二、定義路由信息
    const routes = [{
        path: '/',
        components: {
            default: header,
            sidebar: sidebar,
            main: main
        },
        children: [{
            path: '',
            redirect: 'form'
        }, {
            path: 'form',
            name: 'form',
            component: form
        }, {
            path: 'info/:email/:password',
            name: 'info',
            component: info
        }]
    }]

    const router = new VueRouter({
        routes
    })

    // 三、掛載到當前 Vue 實例上
    const vm = new Vue({
        el: '#app',
        data: {},
        methods: {},
        router: router
    });
</script>

 3、總結

  這一章主要是介紹了命名路由,以及如何經過使用命名視圖在 Vue Router 中將多個組件對應到同一個路由。同時,針對實際使用中咱們常常會遇到的路由傳參,咱們則能夠經過 query 或者是 param 的方式進行參數傳遞。不過,不知道你有沒有注意到,不論是 query 傳參仍是 param 傳參,最終咱們都是經過 vm.$route 屬性獲取到參數信息,這無疑意味着組件和路由耦合到了一塊,全部須要獲取參數值的地方都須要加載 Vue Router,這實際上是很不該該的,所以如何實現組件與路由間的解耦,我將在下一章中進行說明。

 4、參考

  一、從頭開始學習vue-router

  二、單頁面應用路由的兩種實現方式

  三、你須要知道的單頁面路由實現原理

  四、面試官: 你瞭解前端路由嗎?

  五、前端路由實現原理(history)

相關文章
相關標籤/搜索