【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="#/">Home</a> |
  <a href="#/about">About</a> |
  <a href="#/non-existent-path">Broken Link</a>
  <br>
  <component :is="currentView" />
</template>

使用Vue Router+Vue2实现路由

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

1.安装路由

npm i vue-router@3

注意:
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')

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
        }
    ]
})

4.引入router(main.js)

import router from "./router";
new Vue({
  render: (h) => h(App),
  router:router
}).$mount('#app')

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

<template>
<div>
  <h1>Router Demo</h1>

  <router-link to="/home">Home</router-link>||
  <router-link to="/about">About</router-link>
  <router-view></router-view>
</div>


</template>

注意点

  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>Home</h2></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">message</router-link>
        <router-link class="list-group-item" active-class="active" to="/home/news">news</router-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>

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

export default new VueRouter({
    //多个路由
    routes:[
        {
            path:'/about',
            component:About
        },
        {
            path:'/home',
            component:Home,
            children:[
                {
                    path:'message',
                    component:Message
                },
                {
                    path:'news',
                    component:News
                }
            ]
        }
    ]
})

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
                }
            ]
        }
    ]
})

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>&nbsp;&nbsp;
      </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>

在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>

路由优化

路由命名name

<router-link :to="{
        path:'/home/message/details',
        query:{
          id:m.id,
          title:m.title
        }
      }">
          {{ m.title }}
</router-link>

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


                {
                    path:'message',
                    component:Message,
                    children:[
                        {
                            name:'link_detail',
                            path :'details',
                            component:Details
                        }
                    ]
                },

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

 <router-link :to="{
        name:'Link_detail',
        query:{
          id:m.id,
          title:m.title
        }
      }">
          {{ m.title }}
        </router-link>&nbsp;&nbsp;

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

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

<router-link :to="{
        name:'link_detail',
        params:{
          id:m.id,
          title:m.title
        }
      }">

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

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

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

children:[
            {
               name:'link_detail',
               path :'details/:id/:title',
               component:Details
             }
         ]

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

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

路由props

props:{}

			children:[
                        {
                            name:'link_detail',
                            path :'details/:id/:title',
                            component:Details,
                            //props的值会传给Details组件的props
                            props:{a:"1",b:"2"}
                        }
                    ]
<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>

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

props:true(最常用)

			children:[
                        {
                            name:'link_detail',
                            path :'details/:id/:title',
                            component:Details,
                            props:true
                        }
                    ]

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>

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
                                }
                            }
                        }
                    ]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

❀༊烟花易冷ღ

觉得博客写的不错就打赏一下吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值