目录
[(1) push模式:](#(1) push模式:)
[(2) replace模式:](#(2) replace模式:)
[(3) 前进:](#(3) 前进:)
[(4) 后退:](#(4) 后退:)
[(5) 前进或后退几步:](#(5) 前进或后退几步:)
[(6) 使用编程式路由导航的时候,需要注意:](#(6) 使用编程式路由导航的时候,需要注意:)
[1. path ------ 路由匹配路径](#1. path —— 路由匹配路径)
[2. component ------ 匹配时渲染的组件](#2. component —— 匹配时渲染的组件)
[3. children ------ 嵌套子路由配置](#3. children —— 嵌套子路由配置)
[4. name ------ 路由命名](#4. name —— 路由命名)
[5. redirect ------ 路由重定向](#5. redirect —— 路由重定向)
[6. alias ------ 路径别名](#6. alias —— 路径别名)
[7. props ------ 将路由参数作为组件 props](#7. props —— 将路由参数作为组件 props)
[8. meta ------ 路由元信息](#8. meta —— 路由元信息)
前言:
在web开发中分为传统web应用和单页面web应用。传统web应用是指在页面切换时是对多个HTML页面之间的切换。而单页面web应用是指整个页面只有一个HTML页面,点击只是对当前页面中的组件进行切换,属于页面局部更新

单页面应用的优缺点:
单页面应用的优点
1、提供了更加吸引人的用户体验:具有桌面应用的即时性、网站的可移植性和可访问性。
2、单页应用的内容的改变不需要重新加载整个页面,web应用更具响应性和更令人着迷。
3、单页应用没有页面之间的切换,就不会出现"白屏现象" ,也不会出现假死并有**"闪烁"现象**
4、单页应用相对服务器压力小,服务器只用出数据就可以,不用管展示逻辑和页面合成,吞吐能力会提高几倍。
5、良好的前后端分离。后端不再负责模板渲染、输出页面工作,后端API通用化,即同一套后端程序代码,不用修改就可以用于Web界面、手机、平板等多种客户端
单页面应用的缺点:
1、首次加载耗时比较多。
2、SEO问题,不利于百度,360等搜索引擎收录。
3、容易造成CSS命名冲突。
4、前进、后退、地址栏、书签等,都需要程序进行管理,页面的复杂度很高,需要一定的技能水平和开发成本高。
目前较为流行的是单页面应用的开发。
如果想使用Vue去完成单页面应用的开发,需要借助Vue当中的路由机制。
路由route和路由器router
路由器router是来管理/调度各个路由的
对于一个应用来说一般路由器只有一个,路由有多个
路由的组成
路由也是由键值对组成的
key是路径,value是对应的组件
路由本质:一组路由就是一组对应关系
路由器本质:管理多组对应关系

路由的使用
1、创建组件
使用路由之前我们需要先创建好组件,一般我们在src下面创建views文件夹,然后写路由组件

2、安装vue-router
(1) vue2 要安装 vue-router3
npm i vue-router@3
(2) vu3要安装vue-router4
npm i vue-router@4
3、配置vue-router环境并使用
在main.js中
javascript
import Vue from "vue";
import App from "./App.vue";
Vue.config.productionTip = false;
// 导入路由器对象
import router from "./router";
const vm = new Vue({
render: (h) => h(App),
// 一旦使用了vue-router插件,那么new Vue的时候就可以直接传递一个配置项
// 注册路由器对象
router
}).$mount("#app");
console.log(vm);
接着在src目录下,新建一个router文件夹,新建index.js配置路由器对象并暴露
javascript
import VueRouter from "vue-router";
import Vue from 'vue';
Vue.use(VueRouter)
// 导入路由组件
import Home from '@/views/Home';
import NotFound from '@/views/NotFound';
import Detail from '@/views/Detail';
const routes = [
{
path: '/',
redirect: '/home'
},
{
path: '/home',
component: Home,
name: 'home',
// children:[
// {}
// ]
},
{
path: '/detail/:id',
component: Detail,
name: 'detail',
props(route) {
return {
id: route.params.id
}
}
},
{
path: '*',
component: NotFound,
name: 'notfound'
}
]
// 创建路由器
export const router = new VueRouter({
routes
})
它们会被路由配置中的component引入,当路由跳转到对应路径时,这些组件会被渲染到
<router-view>中
配置好后去路由组件使用
javascript
<template>
<div>
<h1>home组件</h1>
<router-link to="/detail">跳转</router-link>
<button @click="$router.push(
'/detail/123'
)">跳转到详情页</button>
</div>
</template>
<script>
export default {
name: 'home',
activated() {
console.log('actived');
},
deactivated() {
console.log('deactivated');
}
}
</script>
<style></style>
然后让路由组件显示
javascript
<template>
<div class="app">
<!-- 路由占位,标记好路由组件显示得位置 -->
<KeepAlive>
<router-view />
</KeepAlive>
</div>
</template>
<script>
export default {
name: 'App',
}
</script>
<style>
</style>
<router-view>是 Vue Router 提供的路由出口。当访问不同 URL 时,匹配到的路由组件会渲染在这里。
<KeepAlive>包裹了<router-view>,作用是缓存被切换掉的路由组件,避免重复创建和销毁,保留组件状态。
注意事项:
1、路由组件一般会和普通组件分开存放,路由组件放到pages或views目录,普通组件放到components目录下。
2、路由组件在进行切换的时候,切掉的组件会被销毁,可用destroyed生命周期钩子证实
3、路由组件的两个属性:route和router
$route:属于自己的路由对象。
$router:多组件共享的路由器对象。
多级路由
多级路由又叫嵌套路由,父路由对应的组件内部自身包含<router-view> ,用于渲染子路由组件,从而形成嵌套的 UI 结构。
创建二级路由组件

配置二级路由关系
javascript
//....
import Hot from "@/views/home/hot.vue";
import Agree from "@/views/home/agree.vue";
import More from "@/views/home/more.vue";
const router = new VueRouter({
// 配置路由规则 配置一组组路由关系,
// 每一组路由关系都是一个对象:
// key:路径==>path
// value:组件==>component
// 第一步:配置好路由关系:key--value
routes: [
{
path: '/home',//注意要以/开头
component: Home,
// children配置项,配置二级路由
children: [
{
// path写法一:路径完整
// path:'/home/hot',//二级路由路径
// path写法二:直接写路径名,不能加/
path: 'hot',
component: Hot//二级路由
},
{
path: 'agree',
component: Agree
},
{
path: 'more',
component: More
}
]
},
//·····
routerLink使用
javascript
<template>
<div>
<!-- 轮播图 -->
<div class="swiper">轮播图</div>
<!-- 二级导航 -->
<div class="subNav">
<!-- 二级路由在使用时,必须把路径写完整 -->
<router-link to="/home/hot">
<h5>正在热卖</h5>
</router-link>
<router-link to="/home/agree">
<h5>值得推荐</h5>
</router-link>
<router-link to="/home/more">
<h5>查看更多</h5>
</router-link>
</div>
//·····
设置二级路由使用位置
javascript
<template>
<div>
<!-- 轮播图 -->
<div class="swiper">轮播图</div>
<!-- 二级导航 -->
<div class="subNav">
//·····
</div>
<!-- 路由组件显示位置 -->
<div>
<router-view />
</div>
</div>
</template>
路由配置项:name
可以给路由起一个名字,这样可以简化to的编写 ,且后期我们在prams传参,需要用到name
**第一步:**在路由关系中,添加name的配置
javascript
{
path: 'agree',
component: Agree,
name: 'agree'
},
**第二步:**使用name,简化to的写法
javascript
<!-- 二级导航 -->
<div class="subNav">
<!-- 二级路由在使用时,必须把路径写完整 -->
<!-- to的写法一 -->
<!-- <router-link to="/home/hot"> -->
<!-- to的写法二 -->
<!-- <router-link :to="{path:'/home/hot'}"> -->
<!-- to的写法三 -->
<router-link :to="{ name: 'hot' }">
<h5>正在热卖</h5>
</router-link>
<router-link to="/home/agree">
<h5>值得推荐</h5>
</router-link>
<router-link to="/home/more">
<h5>查看更多</h5>
</router-link>
</div>
路由query传参
为了提高组件的复用性,可以给路由组件传参
**传递参数:**哪里点击跳转,在哪里传参数
需求:根据电影列表信息,点击不同的电影,查看不同的详情页面
第一步:配置好详情页组件
views/detail.vue
javascript
<template>
<div>
<h1>detail</h1>
</div>
</template>
<script>
export default {
// 接收传递参数
mounted(){
// 当前的路由信息
console.log(this.$route.query,'route');
}
}
</script>
<style></style>
第二步:router/index.js
javascript
routes: [
{
//路由重定向
path: '/',//初始路径
redirect: '/home/hot'
},
{
path:'/detail',
name:'detail',
component:Detail
},
{
//404页面
path: '*',//初始路径
component: '/404'
},
//·····
第三步:传递参数,哪里点击,哪里传递
javascript
<template>
<div>
<ul class="fimls">
<li v-for="item in fimls" :key="item.filmId">
<!-- query传参:
方式一:字符串拼接
语法:to="路由路径?参数名=参数值&参数名=参数值"
方式二:对象的方式
语法::to="{
path:'路由路径',
query:{
参数名:参数值,
参数名:参数值
}
}"
-->
<!-- <router-link to="/detail?a=1&b=2"> -->
<!-- <router-link :to="`/detail?filmId=${item.filmId}`"> -->
<router-link :to="{ path: '/detail', query: { filmId: item.filmId } }">
<img :src="item.poster" alt="" width="80" height="80">
<span>{{ item.name }}</span>
</router-link>
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'News',
data() {
return {
fimls: []
}
},
methods: {
async getMovies() {
let res = await axios({
url: `https://m.maizuo.com/gateway?cityId=310100&pageNum=1&pageSize=10&type=1&k=9724615`,
headers: {
"x-client-info": ' { "a": "3000", "ch": "1002", "v": "5.2.1", "e": "173211553215306425924321281", "bc": "310100" }',
"x-host": "mall.film-ticket.film.list"
}
})
this.fimls = res.data.data.films
console.log(this.fimls);
}
},
created() {
this.getMovies()
}
}
</script>
<style>
.fimls {
height: 500px;
overflow: auto;
}
</style>
第四步:拿取数据
拿到detail组件的路由 this.$route.query ,里面就有传递的参数
javascript
<template>
<div>
<h1>detail:{{ filmId }}</h1>
</div>
</template>
<script>
export default {
data() {
return {
filmId: ''
}
},
// 接收传递参数
mounted() {
// 当前的路由信息
console.log(this.$route.query, 'route');
this.filmId = this.$route.query.filmId
console.log(`通过filmId:${this.filmId}请求数据,进行展示`);
}
}
</script>
路由params传参
**第一步:**新建好detail组件,并配置好路由关系
如果是采用to传递字符串的形式拼接参数: to='路径名/参数1/参数2' ,必须在route/index.js中路径处进行占位
javascript
{
// params传递,必须在路由后进行参数占位
path:'/detail/:filmId/:num2',
name: 'detail',
component: Detail
},
如果是to传递对象的形式:可以不占位
javascript
{
// params传递,必须在路由后进行参数占位
// path:'/detail/:filmId/:num2',
// 如果是对象的形式传参,就不需要占位
path: '/detail',
name: 'detail',
component: Detail
},
**第二步:**传递参数
哪里点击,哪里传递参数
javascript
<template>
<div>
<ul>
<li v-for="film in films" :key="film.filmId">
<!-- params传参
to='路径名/参数1/参数2'
-->
<!-- 1、传递静态数据 -->
<!-- <router-link to="/detail/123/456" class="film"> -->
<!-- 2、传递动态的数据 -->
<!-- <router-link :to="`/detail/${film.filmId}/456`" class="film"> -->
<!-- 3、传递参数:对象的形式,不能用path,必须用name -->
<router-link :to="{
// path: '/detail',
name: 'detail',
params: {
filmId: film.filmId,
num2: 456
}
}" class="film">
<img :src="film.poster" alt="" style="width: 100px;">
{{ film.name }}
</router-link>
</li>
</ul>
</div>
</template>
**第三步:**detail组件接收参数
拿到当前组件的路由关系:this.$route.params
javascript
<template>
<div>
<h1>detail:{{ filmId }}</h1>
</div>
</template>
<script>
export default {
data() {
return {
filmId: ''
}
},
// 接收传递参数
mounted() {
// 当前的路由信息
console.log(this.$route.params);
this.filmId=this.$route.params.filmId
// console.log(`通过filmId:${this.filmId}请求数据,进行展示`);
}
}
</script>
路由的props
props配置主要是为了简化query和params参数的接收。让插值语法更加简洁。
哪个组件接收参数,就在哪个组件路由关系中配置props
三种写法:对象,函数,布尔值写法
javascript
// 创建路由器对象(在路由器对象中配置路由)
const router = new VueRouter({
routes: [
// 路由1
{
name: "sub1",
path: "/subject1/:a1/:a2/:a3",
component: subject,
第一种写法,对象的写法。只能传递固定值
// props: {
// x: "章三",
// y: "李四",
// z: "王二麻",
// },
第二种写法:函数式,这里的$route就是当前路由
// props($route) {
// return {
// a1: $route.params.a1,
// a2: $route.params.a2,
// a3: $route.params.a3,
// };
// },
第三种写法:直接将params方式收到的数据转化为props,这种方式,只针对params传参
props:true
},
{
name: "sub2",
path: "/subject2/:a1/:a2/:a3",
component: subject,
},
],
});
// 暴露路由器对象
export default router;
subject.vue props接收,直接可以使用
javascript
<template>
<div>
<ul class="web">
<li>{{ a1 }}</li>
<li>{{ a2 }}</li>
<li>{{ a3 }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'web',
// 接收路由器中配置的props,简写插值语法的写法
//props: ['x', 'y', 'z']
props: ['a1', 'a2', 'a3']
}
</script>
<style>
.web {
background-color: pink;
}
</style>
router-link的replace属性
浏览器的历史记录是存储在栈这种数据结构当中的。包括两种模式:
(1) push模式(默认的),有历史记录,可以返回上一个页面
(2) replace模式:没有历史记录,不能返回上个一个页面,例如支付页面,如果支付成功,是不允许再回退到支付界面的
开启replace模式
javascript
a.<router-link :replace="true" to=""/>
b. <router-link replace />
编程式路由导航
需求中可能不是通过点击超链接的方式切换路由,也就是说不使用如何实现路由切换。
这种方式,我们叫声明式的路由导航
通过编写代码,完成路由组件的切换,这种方式我们呢交编程式路由导航
声明式路由导航可以通过相关API来完成:
(1) push模式:
javascript
this.$router.push({
name : '',
query : {}
})
(2) replace模式:
javascript
this.$router.replace({
name : '',
query : {}
})
(3) 前进:
javascript
this.$router.forward()
(4) 后退:
javascript
this.$router.back()
(5) 前进或后退几步:
javascript
this.$router.go(2) 前进两步
this.$router.go(-2) 后退两步
(6) 使用编程式路由导航的时候,需要注意:
重复执行push或者replace的API时,会出现以下错误:

这个问题是因为push方法返回一个Promise对象,期望你在调用push方法的时候传递两个回调函数,一个是成功的回调,一个是失败的回调,如果不传就会出以上的错误。所以解决以上问题只需要给push和replace方法在参数上添加两个回调即可。
javascript
....
goDetail(filmId) {
//有历史记录
this.$router.push({
// path:'/detail',
name: 'detail',
params: {
filmId: filmId,
num2: 456
},
query: {
filmId: filmId,
num2: 456
}
}, () => { }, () => { })
....
缓存路由组件
默认情况下路由切换时,路由组件会被销毁。有时需要在切换路由组件时保留组件(缓存起来)。
javascript
<keep-alive>//会缓存所有的路由组件
<router-view/>
</keep-alive>
通过添加以下3种属性,控制路由组件的缓存
include - 字符串或正则表达式或变成动态的属性,解析数组。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式或变成动态的属性,解析数组。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例。
注意: router .js 中的name和vue 组件 的name需要保持一致
javascript
<div class="mycontent">
<!-- 告诉路由器,路由组件显示在这个位置 -->
<!-- 1、只想news组件被缓存,其他组件切换时,还是被销毁 include-->
<!-- 2、除了car组件,其他组件都被销毁 exclude -->
<!-- <keep-alive include="news"> -->
<!-- <keep-alive :include="['news']"> -->
<keep-alive :exclude="['news']" >
<router-view />
</keep-alive>
</div>
activated和deactivated
对于普通的组件来说,有8个生命周期函数,对于路由组件, 除了常规的8个,额外还有2个,
<keep-alive>包裹的路由组件,该组件有两个特有的生命周期函数:activated和deactivated。
activated在路由组件被激活时触发;
deactivated在路由组件失活时触发。
这两个钩子函数的作用是捕获路由组件的激活状态。
javascript
<script>
需求:当组件切换到subject1的时候,每隔1s,输出一句话'工作中····'
当组件切走时,输出'休息中····',并解除定时器
正常情况下,这个功能可以用mounted和beforeDestroy去完成,但当subject1组件用keep-alive保持激活时,
就必须使用activated和deactivated组件了
export default {
name: 'subject1',
// mounted() {
// this.timer = setInterval(() => {
// console.log('工作中····');
// }, 1000)
// },
// beforeDestroy() {
// console.log('休息中···');
// clearInterval(this.timer)
// }
//
activated() {
this.timer = setInterval(() => {
console.log('工作中····');
}, 1000)
},
deactivated() {
clearInterval(this.timer)
console.log('休息中');
}
}
</script>
常用配置项
1. path ------ 路由匹配路径
作用:定义路由的 URL 路径,用于匹配浏览器地址栏的路径。
示例:
javascript
path: '/user'、path: '/user/:id'(动态段)
在多级路由中:父级 path 作为基础路径,子级 path 拼接在后面(可省略开头的 /)。
2. component ------ 匹配时渲染的组件
作用:指定当前路由匹配时要渲染的 Vue 组件。
示例:
javascript
component: Home、component: () => import('@/views/Home.vue')(懒加载)
在多级路由中:父路由的组件通常是一个布局组件(包含 <router-view>),子路由的组件是内容组件。
当一个页面有多个独立的 <router-view>(即多个路由出口)时,需要为每个出口指定不同的组件
使用 components 对象(注意是复数)
3. children ------ 嵌套子路由配置
作用:定义当前路由下的子路由,实现 UI 的嵌套。
类型:数组,每一项又是一个路由配置对象。
示例:
javascript
children: [
{ path: 'profile', component: UserProfile }
]
访问 /user/profile 时,UserLayout 内的 <router-view> 会渲染 UserProfile。
4. name ------ 路由命名
作用:给路由起一个唯一的名字,方便编程式导航或声明式导航时使用。
示例:
javascript
name: 'user'
使用:<router-link :to="{ name: 'user' }"> 或 $router.push({ name: 'user' })
5. redirect ------ 路由重定向
作用:访问当前路径时,自动跳转到另一个路径或路由。
示例:
javascript
{ path: '/', redirect: '/home' }
{ path: '/a', redirect: { name: 'b' } }
6. alias ------ 路径别名
作用:让一个路由拥有多个访问路径。访问别名路径时,URL 会变化,但实际渲染的组件与原始路由相同。
示例:
javascript
{ path: '/home', component: Home, alias: '/' }
访问 / 和 /home 都会渲染 Home 组件。
7. props ------ 将路由参数作为组件 props
作用:简化从 route.params 或 route.query 获取参数的方式,直接通过 props 接收。
三种模式:
javascript
props: true ------ 将 params 作为 props 传入组件。
props: { ... } ------ 静态 props。
props: (route) => ({ ... }) ------ 函数模式,可返回 query/params 等。
示例:
javascript
// 路由配置
{ path: '/user/:id', component: User, props: true }
// 组件中
props: ['id'] // 直接使用 this.id
8. meta ------ 路由元信息
作用:存储自定义数据,用于权限控制、页面标题、过渡动画等逻辑。
示例:
javascript
{ path: '/admin', component: Admin, meta: { requiresAuth: true, title: '管理页' } }
javascript
获取:$route.meta.requiresAuth