一、什么是Vue-router
Vue-router是Vue.js的官方路由。它与Vue.js核心深度集成,让用 Vue.js 构建单页应用变得轻而易举。它是Vue.js 的一个插件库,专门用来实现SPA 应用。
SPA
单页 Web 应用(single page web application,SPA),整个应用只有一个完整的页面,点击页面中的导航链接不会刷新页面,只会做页面的局部更新,数据需要通过ajax请求获取。
路由
一个路由就是一组映射关系,路由分为前端路由和后端路由。路由的工作过程,当浏览器路径改变时,展示其对应的路由组件。
二、路由的基本使用
安装
npm
npm i vue-router@4
yarn
yarn add vue-router@4
注:vue2请安装vue-router@3,vue3安装其对应的vue-router@4,本篇使用Vue2实现路由。
配置路由
-
创建文件夹store,再其创建index.js文件,用于配置路由
-
一般来说,components文件主要用来存放一般组件,即未参与路由使用的组件,新建文件夹pages用于专门存放路由组件,使其文件脉络清晰。
index.js
// 该文件用于创建整个应用的路由器
import VueRouter from 'vue-router'
// 引入对应的路由组件
import About from '../pages/About'
import Home from '../pages/Home'
// 创建并暴露一个路由器
export default new VueRouter({
routes: [{
// 路径
path: '/about',
// 路由组件名
component: About
},
{
path: '/home',
component: Home
}]
})
main.js
// 引入vue
import Vue from 'vue'
import App from './App.vue'
// 引入路由
import VueRouter from 'vue-router'
import router from './router'
Vue.config.productionTip = false
// 使用路由,路由是Vue.js的一个插件库
Vue.use(VueRouter)
const vm = new Vue({
el: '#app',
render: h => h(App),
// 创建路由配置项
router,
})
使用路由
App.vue
<template>
<div>
<!-- Vue中借助router-link标签实现路由的切换 类似于a标签 -->
<!-- active-class="active" 用来做选中时的样式切换 -->
<router-link active-class="active" to="/about">
About
</router-link>
<router-link active-class="active" to="/home">
Home
</router-link>
<div>
<!-- 指定组件的呈现位置 -->
<!-- Home以及About组件的内容,将于此处展示 -->
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name: 'App',
}
</script>
注:每个路由都有自己的$route属性,用于存放该路由的基本信息,而整个文件则存在一个$router属性,可以获得其他route的基本信息。通过切换路由组件隐藏时,默认是销毁了该路由组件,显示时则是重新挂载该路由组件。
三、多级路由
多级路由实为路由之间的嵌套。在路由的基本使用中,我们注册了Home和About路由组件,当在App组件中使用切换路由选项,则是将对应的路由显示在App.vue中的<router-view>标签中。现在我们同样创建两个组件,名为News和Message,并为其注册为路由组件,当在Home组件使用切换路由选项时,则是将对应的路由显示在Home.vue中的<router-view>标签中。
index.js
// 该文件用于创建整个应用的路由器
import VueRouter from 'vue-router'
// 引入路由组件,Message和News为我们新引入的路由组件
import About from '../pages/About'
import Home from '../pages/Home'
import Message from '../pages/Message'
import News from '../pages/News'
// 创建并暴露一个路由器
export default new VueRouter({
routes: [{
path: '/about',
component: About
},
{
path: '/home',
component: Home,
// 在Home路由配置项中,配置其子路由,使用children配置项
// 并且path路径不需要/开头
children: [{
path: 'message',
component: Message
},
{
path: 'news',
component: News
}]
}]
})
Home.vue
<template>
<div>
<h2>Home组件内容</h2>
<!-- 用于切换路由组件,并选中用于展示的路由组件 -->
<div>
<ul>
<li>
<router-link active-class="active" to="/home/news">
News
</router-link>
</li>
<li>
<router-link active-class="active" to="/home/message">
Message
</router-link>
</li>
</ul>
<!-- 在原先基础上新增<router-view>用于展示被选中的路由内容 -->
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name: 'Home',
}
</script>
注:路由跳转的路径要写完整(/home/news),如只写(/news)为错误写法。配置路由规则,应使用children配置项。
四、query参数
现在我们在新配置一个路由组件,名为Details。并在Message中嵌套该路由组件,并传入data参数,现将Message中的data数据传到Details中,Details读取数据,并且当Message切换路由时,Details将对应数据展示到Message组件的<router-view>标签中。在路由中我们通过query实现数据传递。
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: [{
path: '/about',
component: About
},
{
path: '/home',
component: Home,
children: [{
path: 'message',
component: Message,
// 在Home路由下的Message路由中配置子路由Details,也应使用children配置项
children: [{
path: 'detail',
component: Detail
}]
},
{
path: 'news',
component: News
}]
}]
})
Message.vue
<template>
<div>
<ul>
<li v-for="m in messageList" :key="m.id">
<!-- 跳转路由并携带query参数,to的字符串写法 -->
<!-- <router-link
:to="`/home/message/detail?
id=${m.id}&title=${m.title}`">
{{m.title}}
</router-link> -->
<!-- 跳转路由并携带query参数,to的对象写法 -->
<router-link :to="{
path:'/home/message/detail',
query:{
id:m.id,
title:m.title
}
}">
{{m.title}}
</router-link>
</li>
</ul>
<!-- 对应的Details路由组件将展示于此标签中 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'Message',
// 在data中设置一个messageList数组对象
data() {
return {
messageList: [
{id:'001',title:'a'},
{id:'002',title:'b'},
{id:'003',title:'c'}
]
}
},
}
</script>
Details.vue
<template>
<ul>
<!-- 使用$route.query读取数据 -->
<li>消息编号:{{$route.query.id}}</li>
<li>消息名称:{{$route.query.title}}</li>
</ul>
</template>
<script>
export default {
name: 'Detail',
}
</script>
五、命名路由
简化可以简化路由的跳转,我们可以在配置路由中,增加一个name配置项。
export default new VueRouter({
routes: [{
// 命名路由
name: 'guanyu',
path: '/about',
component: About
},
})
<template>
<div>
<!-- 指定组件的呈现位置 -->
<!-- 通过name配置项跳转路由,通常使用于多级路由,用于简化跳转路由路径 -->
<router-link active-class="active" :to"{name:'guanyu'}">
About
</router-link>
<router-link active-class="active" to="/home">
Home
</router-link>
<div>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name: 'App',
}
</script>
六、params参数
该参数与query参数作用一样,都是为了传递数据使用。
index.js
export default new VueRouter({
routes: [
{
path: '/home',
component: Home,
children: [{
path: 'message',
component: Message,
children: [{
// 命名路由
name: 'xiangqing',
// 表明在
path: 'detail/:id/:title',
component: Detail
}]
}]
}]
})
Message.vue
<template>
<div>
<ul>
<!-- 跳转路由并携带params参数,to的字符串写法 -->
<li v-for="m in messageList" :key="m.id">
:to="`/home/message/detail/id=${m.id}/&title=${m.title}`">
{{m.title}}
</router-link>
<!-- 跳转路由并携带params参数,to的对象写法 -->
<!-- <router-link :to="{
name: 'xiangqing',
<!-- 如果使用params传递参数,不可以使用path配置项,只能用name -->
params:{
id:m.id,
title:m.title
}
}">
{{m.title}}
</router-link> -->
</li>
</ul>
<router-view></router-view>
</div>
</template>
Details.vue
<template>
<ul>
<!-- 使用$route.params读取数据 -->
<li>消息编号:{{$route.params.id}}</li>
<li>消息名称:{{$route.params.title}}</li>
</ul>
</template>
<script>
export default {
name: 'Detail',
}
</script>
注:使用params参数传参,必须使用name配置项,而不是path。
七、路由的props配置
路由的props配置让路由更方便的接收到参数。
// props第一种写法,值为对象,该对象中的所有key-value的形式传给组件
// 使用该方式传递数据,数据单一
props: {a:1,b:'hello'}
// props第二种写法,值为布尔值,若布尔值为真,就会把该路由组件接收到的params参数,
// 以props的形式传给组件
props: true
// 第三种写法,值为函数,使用该方法更加灵活,可读取$route中的数据
props($route) {
return {id:$route.params.id,title:$route.params.title}
}
// 亦可传递query中的数据
props($route) {
return {id:$route.query.id,title:$route.query.title}
}
<!-- Details组件中,可以接收到上述三种方式传递的数据 -->
<!-- 在配置项props中接收 -->
<template>
<ul>
<li>消息编号:{{id}}</li>
<li>消息名称:{{title}}</li>
</ul>
</template>
<script>
export default {
name: 'Detail',
props: ['id','title']
}
</script>
八、replace和push属性
<router-link>标签中有replace和push两个属性,在官方文档中是这样解释的:push,通过在历史堆栈中推送一个 entry,以编程方式导航到一个新的 URL;replace,通过替换历史堆栈中的当前 entry,以编程方式导航到一个新的 URL。简单来说就是使用push属性,我们可以通过浏览器单击以返回按钮,即左上角向左箭头返回上一步,以及单机以继续按钮返回下一步操作。而使用replace属性则是无法返回到使用该属性的路由组件。<router-link>标签默认值为push属性。
<!-- 开启replace属性 -->
<router-link replace>News</router-link>
九、编程式路由导航
我们之前都是借助<router-link>标签,实现路由的跳转,该标签与a标签形式类似,但如果我们想让其他标签如button标签实现路由跳转,那使用<router-link>则做不到。我们借助编程式路由导航,使路由跳转更加灵活。
<template>
<div>
<ul>
<li v-for="m in messageList" :key="m.id">
<button @click="pushShow(m)">push一下</button>
<button @click="replaceShow(m)">replace一下</button>
</li>
</ul>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'Message',
data() {
return {
messageList: [
{id:'001',title:'a'},
{id:'002',title:'b'},
{id:'003',title:'c'}
]
}
},
methods: {
pushShow(m) {
this.$router.push({
name: 'xiangqing',
params:{
id:m.id,
title:m.title
}
})
},
replaceShow(m) {
this.$router.replace({
name: 'xiangqing',
params:{
id:m.id,
title:m.title
}
})
}
}
}
</script>
我们创建两个button,通过这两个按钮来实现路由的切换以及路由的跳转,首先我们分别给两个路由设置点击事件,事件名称后的(m)为传递m参数。其次编写这两个点击事件的方法,通过$router中的push和replace属性(与上述原理一样)实现路由跳转。
十、缓存路由组件
通过第二点路由的基本使用可知,当路由进行切换时,被隐藏的那个路由组件实际是被销毁了,而展示路由组件则是被重新挂载,这就导致当我们某个路由组件存在输入数据时,由于切换路由,导致该路由组件被销毁,输入数据与之销毁。因此当我们切换路由时不该销毁该路由,而是通过缓存保持路由的挂载状态,切换路由时,输入数据仍然保留。
<keep-alive include="News,Message">
<router-view></router-view>
</keep-alive>>
通过使用keep-alive标签将router-view标签进行包裹,若没有特别指示,则是将所有在这展示的路由进行缓存,如仅想指定个别路由进行缓存,则通过include属性,添加需要进行缓存的路由组件名,若需要多个路由进行缓存,仅需使用逗号分隔开。
十一、路由守卫
。。。
十二、两个生命周期钩子
路由组件所独有的两个生命周期钩子,用于捕获路由组件的激活状态。activated:路由组件被激活时触发,deactivated:路由组件失活时触发。
activated():在vue对象存活的情况下,进入当前存在activated()函数的页面时,一进入页面就触发;可用于初始化页面数据、keepalive缓存组件后,可执行方法。
deactivated():离开组件时执行。
注:activated()和deactivated()只有在<keep-alive>标签包裹的时候才有效
十三、路由器的两种工作模式
路由器中有两种工作模式hush和history。hash模式:它在内部传递的实际 URL 之前使用了一个哈希字符(#);history模式:用于路由实现历史记录。
hash模式:
-
地址中永远带着#,不美观
-
若以后将地址通过第三方手机app分享给,若app校验严格,则地址会被标记为不合法。
-
兼容性好
history模式:
-
地址干净,美观
-
兼容性和hash模式相比略差
-
应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题