[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)

相关文章
相关标签/搜索