Vue路由(route)-编程式路由导航

为什么会需要编程式路由导航?

  • 我们之前学习的Vue路由(route)是通过标签实现页面的跳转的(声明式路由导航),而标签最终会解析成<\a>标签渲染到页面上,但是我们都知道真正实际的开发中不可能全部路由组件都由<\a>标签来引导,有时候,我们会设置一个

实现原理:

  • 所谓”编程式路由导航”其实就相当于使用全局路由器($router)身上的一些特殊的api配合Vue组件methods方法来操控浏览器的历史记录

作用:

  • 使路由的跳转无需再借助标签,更加灵活!

有5个常用的api

image

使用方法:

  • 1.push(压栈式路由跳转,会给浏览器留下历史记录)

    // 字符串式
    this.$router.push('home')

    // 对象式
    this.$router.push({ path: 'home' })

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

    // 带查询参数(query或者params),变成 /message?id=666
    this.$router.push({ path: 'message', query: { id: '666' }})
  • 2.replace(取代式路由跳转,不会给浏览器留下历史记录)2.Replace(取代式路由跳转,不会给浏览器留下历史记录)

    // 字符串
    this.$router.replace('home')

    // 对象
    this.$router.replace({ path: 'home' })

    // 命名的路由
    this.$router.replace({ name: 'user', params: { userId: 123 }})

    // 带查询参数,变成 /register?plan=private
    this.$router.replace({ path: 'register', query: { plan: 'private' }})
  • 3.back(相当于浏览器左上角的 ”《-”)

    this.$router.back() //实现浏览器的回退(相当于浏览器左上角的 “<-” )
  • 4.forward(相当于浏览器左上角的 ”->”)

    this.$router.forward() //实现浏览器的前进(相当于浏览器左上角的 “->” )
  • 5.go(即可实现浏览器的回退又可实现浏览器的前进)

    //靠go(参数),这里面的参数决定浏览器是回退还是前进
    //当参数为-n时,回退n步,当参数为+n时,前进n步 
    this.$router.go() //可前进也可后退

案例代码实现:

  • router-index.js

    // 这里配置路由(创建整个应用页面的路由器)

    // 首先引入路由
    import VueRouter from "vue-router";

    // 引入各个组件
    import About from '../pages/About'
    import Home from '../pages/Home'
    import Message from '../pages/Message'
    import News from '../pages/News'
    import Detail from '../pages/Detail'

    // 创建并向外暴露路由器
    export default new VueRouter({
        // 一级路由
        routes:[
            {  
                //设置管理路由:About
                path:'/about',
                component: About
            },
            {  
                //设置管理路由:Home
                path:'/home',
                component: Home,
               
                // 二级路由(children属性)
                children:[//通过children配置子级路由
                    {
                        // 使用二级路由过后的path不需要再加上"/"
                        path:'message',
                        component: Message,

                        // 使用三级路由
                        children:[
                            {
                                // 给这个三级路由命名未"xiangqing"
                                name : 'xiangqing',
                                path:'detail',
                                component: Detail,

                                props(route){//这里传入route($route也可以)就能获取到本地路由上的所有数据
                                    return {
                                        // 在通过对象赋值的方式传递数到指定的组件(route组件)即可
                                        id: route.query.id,
                                        title: route.query.title
                                    }
                                }
                            }
                        ]
                    },
                    {
                        // 使用二级路由过后的path不需要再加上"/"
                        path:'news',
                        component: News,
                    }
                ]
            },

        ]
    })
  • Message组件

    <template>
        <div>
            <ul>
                <li  v-for="m in messageList" :key="m.id">
                    <!-- 这里使用常规的方法然url携带query[与ajax里面的query参数一致]参数 -->
                    <!-- query参数是用于携带url信息的 -->
                    <!-- 跳转路由并携带query参数 -->
                    <router-link :to="{
                        // 使用路由的名字来调用路由更加简单
                        name : 'xiangqing',
                        query: {
                            id: m.id,
                            title: m.title},
                        }"
                    >{{m.title}}</router-link>
                    <!-- 将数据 m 参数传过去methods方便使用 -->
                    <button @click="push(m)">push查看</button>
                    <button @click="replace(m)">replace查看</button>
                </li>
            </ul>
            <hr>
            <router-view></router-view>
        </div>
    </template>

    <script>
        export default {
            name : 'News',
            data() {
                return {
                    messageList : [
                        {id:'001',title:'消息001'},
                        {id:'002',title:'消息002'},
                        {id:'003',title:'消息003'},
                    ]
                }
            },
            // 使用methods配合 编程式路由导航 实现路由的切换更加灵活
            methods: {
                // 压栈式路由跳转,会给浏览器留下历史记录(相当于点击路由链接)
                push(m){//这里接收上面模板传过来的m参数
                    // console.log(this.$router);
                    this.$router.push({
                        // 使用路由的名字来调用路由更加简单
                        name : 'xiangqing',
                        query: {
                            id: m.id,
                            title: m.title},
                    })
                },
                // 取代式路由跳转,不会给浏览器留下历史记录(相当于用新路由替换当前路由)
                replace(m){//这里接收上面模板传过来的m参数
                    this.$router.replace({
                        // 使用路由的名字来调用路由更加简单
                        name : 'xiangqing',
                        query: {
                            id: m.id,
                            title: m.title},
                    })
                }
            },
        }
    </script>
  • Banner组件

    <template>
        <div class="row">
          <div class="col-xs-offset-2 col-xs-8">
            <div class="page-header"><h2>Vue Router Demo</h2></div><br>
            <!-- 绑定back()-api回退浏览器历史记录 -->
            <button @click="backoff">回退</button>
            <!-- 绑定forward()-api前进浏览器历史记录 -->
            <button @click="ahead">前进</button>
            <!-- 绑定go(n)-api控制浏览器历史记录的回退和前进 -->
            <button @click="go">测试go</button>
          </div>
        </div>
    </template>

    <script>
        export default {
            name : 'Banner',
            methods: {
              backoff(){
                // 直接调用back的api即可(请求[返回]上一个记录路由)
                this.$router.back()
              },
              ahead(){
                // 直接调用forward的api即可(请求[返回]上一个记录路由)
                this.$router.forward()
              },
              go(){
                // go需要传递一个数值型参数进去控制浏览器历史记录的前进和后退
                this.$router.go(-2)//按着浏览器的历史记录回退2步
              }
            }
        }
    </script>
  • Detail组件

    <template>
        <ul>
            <li>消息编号:{{id}}</li>
            <li>消息标题:{{title}}</li>
        </ul>
    </template>

    <script>
        export default {
            name : 'Detail',
            // 方法三(直接接收query传过来的参数可直接在模板上使用)
            // 设置props接收路由传过来的数据
            props:['id','title'],

            mounted(){
                // 输出本地的route发现里面多了一个params参数
                // params参数里面携带者url传过来的数据
                console.log(this.$route);
            }  
        }
    </script>

结果展示:

image

缓存路由组件

  • 我们都知道,经过路由去指向组件的跳转的时候,当指向从一个组件跳向另一个组件的时候,流程是:先销毁前一个组件,再挂载下一个组件,即:隐藏组件实质是销毁组件,显示组件实质是挂载组件。但是有些时候,我们想保留前一个组件再跳到下一个组件,即让前一个组件保持挂载,这时我们就用到了”缓存路由组件

应用场景:

  • 是当我们想对现在这个页面如数一些信息时,但此时我们有需要跳转到下一个页面去查找需要填入的信息,这时我们需要保持上一个页面填好的信息,待我们在下一个页面查找到我们需要的信息时,返回上一个页面,我们之前填写的信息还在而不是需要重新填写
    image

缓存路由组件:<keep-alive include=”组件名”></keep-alive>

  • 作用:让不展示的路由组件保持挂载,不被销毁。
  • 使用方法
    <keep-alive include="要保持挂载的组件名"> 
       <router-view></router-view>
    </keep-alive>

案例代码展示:

  • Home组件

    <template>
        <div>
            <h2>Home组件内容</h2>
            <div>
                <ul class="nav nav-tabs">
                    <li>
                        <!-- 使用路由提供的router-link实现页面跳转-->
                        <!-- (router-link最终会转化为a白标签显示到页面上)  -->
                        <!-- 使用active-class属性能够实现响应式切换css样式 -->
                        <!-- 使用to="/指定组件拼接的网址url(在路由器里面设定的path属性)" -->
                        <!-- 这里的to属性路径要补全: /home/news(指定跳向一级路由下的二级(嵌套或多级)路由)-->
                    <router-link class="list-group-item" active-class="active" to="/home/news">News</router-link>
                    </li>
                    <li>
                        <!-- 使用路由提供的router-link实现页面跳转-->
                        <!-- (router-link最终会转化为a白标签显示到页面上)  -->
                        <!-- 使用active-class属性能够实现响应式切换css样式 -->
                        <!-- 使用to="/指定组件拼接的网址url(在路由器里面设定的path属性)" -->
                        <!-- 这里的to属性路径要补全: /home/news(指定跳向一级路由下的二级(嵌套或多级)路由)-->
                    <router-link class="list-group-item" active-class="active" to="/home/message">Message</router-link>
                    </li>
                </ul>
                <!-- 缓存路由组件 -->
                <div>
                    <!-- 缓存多个路由组件(不写include属性默认缓存该父组件管辖下所有的子组件) -->
                    <!-- <keep-alive :include="['News','Message']"> -->
                       
                    <!-- 缓存一个路由组件(不写include属性默认缓存该父组件管辖下所有的子组件) -->
                    <keep-alive include="News">
                        <!-- 使用vue-router插件库提供的router-view标签实现指定区域显示组件 -->
                        <router-view></router-view>
                    </keep-alive>
                </div>
            </div>
        </div>
    </template>

    <script>
        export default {
            name : 'Home' ,
        }
    </script>
  • News组件

    <template>
        <ul>
            <!-- 给这些新闻后面加入输入框 -->
            <li>news001</li><input type="text">
            <li>news002</li><input type="text">
            <li>news003</li><input type="text">
        </ul>
    </template>

    <script>
        export default {
            name : 'News'
        }
    </script>

结果展示:

image