• 【Vue】路由vue-Router


    服务端路由

    服务端路由时指的是服务器根据用户访问的 URL 路径返回不同的响应结果。

    在传统的服务端渲染的 web 应用中点击一个链接时,浏览器会从服务端获得全新的 HTML页面,然后重新加载整个页面。

    然而,在单页面应用中,客户端的 JavaScript 可以拦截页面的跳转请求,动态获取新的数据,无需重新加载的情况下更新当前页面。
    这样通常可以带来更顺滑的用户体验,尤其是在更偏向“应用”的场景下,因为这类场景下用户通常会在很长的一段时间中做出多次交互。

    在这类单页应用中,“路由”是在客户端执行的。一个客户端路由器的职责就是利用诸如 History API 或是 hashchange 事件这样的浏览器 API 来管理应用当前应该渲染的视图。

    路由的应用场景:

    单页面应用(SPA应用):

    1. 顾名思义导航栏不变,内容栏改变的应用。
    2. 内容栏根据导航栏的选择变化的同时,页面不会跳转,也就是说不会产生新的请求。
    3. js拦截页面的跳转请求,动态的获取新的数据,路径也会随之变化。
    4. 数据需要通过ajax的请求获取。

    路由

    1. 路由就是多个key-value的对应关系。
    2. 每一个路由都需要路由器的支持。

    监听浏览器 hashchange 事件实现路由

    如果你只需要一个简单的页面路由,而不想为此引入一整个路由库,你可以通过动态组件的方式,监听浏览器 hashchange 事件或使用 History API 来更新当前组件。

    <script>
    import About from "./components/About.vue";
    import Home from "./components/Home.vue";
    import NotFound from "./components/Not Found.vue";
    
    const routes = {
      //路由默认跳转到Home组件
      '/': Home,
      '/about': About
    }
    
    export default {
      data() {
        return {
          currentPath: window.location.hash
        }
      },
      computed: {
        //计算属性的方法,响应式的,缓存
        currentView() {
          //过滤#,匹配路由
          return routes[this.currentPath.slice(1) || '/' ] || NotFound
        }
      },
      mounted() {
        window.addEventListener('hashchange', () => {
          //只要window变化了就,把当前的路径给App组件下的属性this.currentPath
          this.currentPath = window.location.hash
        })
      }
    }
    script>
    
    <template>
      <a href="#/">Homea> |
      <a href="#/about">Abouta> |
      <a href="#/non-existent-path">Broken Linka>
      <br>
      <component :is="currentView" />
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    使用Vue Router+Vue2实现路由

    用 Vue + Vue Router 创建单页应用非常简单:通过 Vue.js,我们已经用组件组成了我们的应用。当加入 Vue Router 时,我们需要做的就是将我们的组件映射到路由上,让 Vue Router 知道在哪里渲染它们。

    1.安装路由

    npm i vue-router@3
    
    • 1

    注意:
    vue3对应的vue-router版本是4
    vue2对应的vue-router版本是3

    我这里是vue2

    2.导入VueRouter插件(main.js)

    import Vue from 'vue'
    import App from './App.vue'
    import VueRouter from "vue-router"
    import './assets/main.css'
    //关闭vue的生产提示
    Vue.config.productionTip = false
    //使用路由器插件
    Vue.use(VueRouter)
    new Vue({
      render: (h) => h(App),
    }).$mount('#app')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.编写创建路由器router(并暴露)的js文件(router/index.js)

    import VueRouter from "vue-router";
    import Home from "../components/Home";
    import About from "../components/About";
    import NotFound from "../components/Not Found";
    //创建路由器并暴露
    export default new VueRouter({
        //多个路由
        routes:[
            {
                path:'/about',
                component:About
            },
            {
                path:'/Home',
                component:Home
            }
        ]
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4.引入router(main.js)

    import router from "./router";
    new Vue({
      render: (h) => h(App),
      router:router
    }).$mount('#app')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    5. 使用router-link激活路由以及路由视图的展示

    <template>
    <div>
      <h1>Router Demoh1>
    
      <router-link to="/home">Homerouter-link>||
      <router-link to="/about">Aboutrouter-link>
      <router-view>router-view>
    div>
    
    
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    注意点

    1. 当路由组件进行切换的时候,当前组件会被销毁,然后挂载新的组件。
    2. 通过路由器配置并且渲染的组件,我们称路由组件
    3. 多个路由共用的是同一个路由器

    路由嵌套

    现在定制一个需求
    当我点击Home路由组件的时候,我希望它再来一个嵌套的路由。因此我们就需要对Home组件也进行路由的激活和视图展示:

    <template>
    
      <div class="row">
        <div class="row">
          <div class="col-xs-offset-2 col-xs-8">
            <div class="page-header"><h2>Homeh2>div>
          div>
        div>
        <div class="col-xs-offset-2 col-xs-2">
          <div class="list-group">
            <router-link class="list-group-item" active-class="active" to="/home/message">messagerouter-link>
            <router-link class="list-group-item" active-class="active" to="/home/news">newsrouter-link>
          div>
        div>
    
        <div class="col-xs-6">
          <div class="panel">
            <div class="panel-body">
              <router-view>router-view>
            div>
          div>
        div>
    
      div>
    template>
    
    <script>
    export default {
      name: "Home",
      mounted() {
        console.log("Home组件被挂载了",this);
      }
    }
    script>
    
    <style scoped>
    *{
      margin: 0;
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    那么新增了两个子路由,对应的,就必须去路由器添加:

    export default new VueRouter({
        //多个路由
        routes:[
            {
                path:'/about',
                component:About
            },
            {
                path:'/home',
                component:Home,
                children:[
                    {
                        path:'message',
                        component:Message
                    },
                    {
                        path:'news',
                        component:News
                    }
                ]
            }
        ]
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    children属性作为子路由的拓展,值得注意的是子路由的path下不能像父级路由那样添加/,因为vue-router底层的只要匹配到children属性,就会帮我们省略这一步骤。

    路由传参

    假如我现在有这么一个需求
    在这里插入图片描述

    当我点击哪个message,就显示哪个message的信息。

    于是我们需要在嵌套一个三级子路由,并且由于对象格式相同,我们可以放到一个新的组件里,然后利用路由传参实现。

    1.定义一个新的组Details.vue

    2. 配置路由

    
    export default new VueRouter({
        //多个路由
        routes:[
            {
                path:'/about',
                component:About
            },
            {
                path:'/home',
                component:Home,
                children:[
                    {
                        path:'message',
                        component:Message,
                        children:[
                            {
                                path :'details',
                                component:Details
                            }
                        ]
                    },
                    {
                        path:'news',
                        component:News
                    }
                ]
            }
        ]
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    3.Message组件下以对象格式传参

    <template>
      <div>
        <ul>
          <li v-for="m in messageList" :key="m.id">
            <router-link :to="{
            path:'/home/message/details',
            query:{
              id:m.id,
              title:m.title
            }
          }">
              {{ m.title }}
            router-link>  
          li>
    
        ul>
        <router-view>router-view>
      div>
    template>
    
    <script>
    export default {
      name: "Message",
      data() {
        return {
          messageList: [
            {id: 1, title: "message01"},
            {id: 2, title: "message02"},
            {id: 3, title: "message03"},
          ]
        }
      }
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在Message组件下创建属性messageList集合,然后通过v-for遍历它并且显示在列表标签内,最后用router-link :to可以携带一个对象,path:url路径,query:参数。注意query的值也必须是一个对象格式的。

    4.Details.vue取参数进行回显

    <template>
    <ul>
      <li>消息编号:{{$route.query.id}}li>
      <li>消息标题:{{$route.query.title}}li>
    ul>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    路由优化

    路由命名name

    <router-link :to="{
            path:'/home/message/details',
            query:{
              id:m.id,
              title:m.title
            }
          }">
              {{ m.title }}
    </router-link>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在开发环境中,如果我们真的用path属性去表示路由的路径,这实在过于冗余,因此可以在路由器的配置下做手脚:每一个路由可以有一个唯一的名字,供name属性引用

    
                    {
                        path:'message',
                        component:Message,
                        children:[
                            {
                                name:'link_detail',
                                path :'details',
                                component:Details
                            }
                        ]
                    },
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    那么routeLink下的:to的值便不再需要path属性,而是用name来表示路由的名字。

     <router-link :to="{
            name:'Link_detail',
            query:{
              id:m.id,
              title:m.title
            }
          }">
              {{ m.title }}
            </router-link>&nbsp;&nbsp;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    利用路由params实现ResultFul风格请求

    由于query属性是一对key-value的形式作为携带的参数。
    如果想要实现ResultFul的请求方式,也就是说在url上隐藏key的显示,只显示value,也没有?和&作为分割。

    <router-link :to="{
            name:'link_detail',
            params:{
              id:m.id,
              title:m.title
            }
          }">
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    更为简洁的写法::to表示里面只能是对象 ``用表示里面的只能是字符串,因此结合起来就可以表示字符串的对象了。

    <router-link :to="`/home/message/details/${m.id}/${m.title}`">
    
    • 1

    以:id 的形式作为占位符,id是params下的属性。

    children:[
                {
                   name:'link_detail',
                   path :'details/:id/:title',
                   component:Details
                 }
             ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    那么在回显的时候,不再是$route.query.id,而是 $route.params.id

    <template>
    <ul>
      <li>消息编号:{{$route.params.id}}li>
      <li>消息标题:{{$route.params.title}}li>
    ul>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    路由props

    props:{}

    			children:[
                            {
                                name:'link_detail',
                                path :'details/:id/:title',
                                component:Details,
                                //props的值会传给Details组件的props
                                props:{a:"1",b:"2"}
                            }
                        ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    <template>
      <ul>
        <li>消息编号:{{ id }}</li>
        <li>消息标题:{{ title }}</li>
        a:{{ a }}
        b:{{ b }}
      </ul>
    </template>
    
    <script>
    export default {
      name: "Details",
      mounted() {
        console.log("Details被挂载了", this)
      },
      props: ['a', 'b']
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这种做法可以在某个路由下通过props:对象 的形式去携带一个对象给路由组件,那么路由组件可以通过props:数组 的形式表示这些对象属性。缺点是只能携带定值。

    props:true(最常用)

    			children:[
                            {
                                name:'link_detail',
                                path :'details/:id/:title',
                                component:Details,
                                props:true
                            }
                        ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    props:true表示该路由组件携带的params参数,以props的形式传给当前路由组件

    <template>
    <ul>
      <li>消息编号:{{id}}</li>
      <li>消息标题:{{title}}</li>
    
    </ul>
    </template>
    
    <script>
    export default {
      name: "Details",
      mounted() {
        console.log("Details被挂载了",this)
      },
      props:['id','title']
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    props(){}(插一句,用的不是很多)

    由于上一种方式只能把组件携带的params参数传递给props,如果你想组件携带的query参数传递给props,那么这里演示一个通过props函数:将携带的query参数传递给props,但是不要忘记把请求的方式改回query参数。

    		 children: [
                            {
                                name: 'link_detail',
                                path: 'details',
                                component: Details,
                                props($routes) {
                                    return {
                                        id: $routes.query.id,
                                        title:$routes.query.title
                                    }
                                }
                            }
                        ]
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

  • 相关阅读:
    天池比赛记录
    【数据结构】手撕排序算法(中)交换排序 (冒泡排序、快速排序的递归方式(挖坑法、前后指针法、左右指针法))、归并排序的递归方式
    RedisTemplate的操作和用法
    驱动开发课程LED点亮
    et al和etc区别
    华为机试 - 最大社交距离
    进程与线程
    网络安全的主要威胁及应对方法
    没有哪件事比可视化运维大屏上线更有意义了!这一天等了好久
    申请发明专利的流程及时间
  • 原文地址:https://blog.csdn.net/qq_53635765/article/details/126916545