Vue笔记-系列
Vue笔记[一]-初识
Vue笔记[二]-组件化
Vue笔记[三]-ToDoList
Vue笔记[四]-动画、Vuex
Vue笔记[五]-路由
Vue笔记[六]-Vue3
Vite、Pinia、Router
QX-AI
GPT-4
QX-AI初始化中...
暂无预设简介,请点击下方生成AI简介按钮。
介绍自己
生成预设简介
推荐相关文章
生成AI简介

路由route

前端路由用于实现 SPA应用(单页Web应用)

SPA应用:
(1) 整个应用只有一个完整的页面
(2) 点击导航区不刷新页面,只做页面的局部更新
(3) 数据需要通过 ajax 请求获取

每个路由都是路径组件映射关系,当浏览器的路径改变时,对应的组件就会显示

路由基本使用

在 Vue 中使用路由需安装 vue-router 插件

安装: npm install vue-router ,最新版本仅支持 Vue3,Vue2 需使用 vue-router@3

使用步骤:
(1) 创建路由器
(2) 注册路由
(3) 使用路由
(4) 编写路由组件

注意:
(1) 不断切换路由时,路由组件在重复地销毁和挂载,即重复地经过完整的生命周期
(2) vue-router 插件会向 vm 和 vc 身上添加 $route(当前路由) 和 $router(全局路由器) 两个属性

1、创建路由器:
通常在 src 目录下新建 router/index.js

使用 new VueRouter() 创建路由器实例

/router/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 该文件用于创建路由器
import VueRouter from 'vue-router';
import About from '@/pages/About.vue';
import Home from '@/pages/Home.vue';

// 创建路由器
export default new VueRouter({
routes: [
// 一级路由
{
// 路由的路径
path: '/about',
// 路由对应展示的组件
component: About
},
{
path: '/home',
component: Home,
},
]
});

2、注册路由:
new Vue() 时传入刚刚创建好的路由器实例

因为 vue-router 是插件,还要 Vue.use() 安装插件

main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Vue from "vue";
import App from "./App.vue";
import VueRouter from "vue-router";
// 引入路由器
import router from "@/router"

Vue.config.productionTip = false;

Vue.use(VueRouter)

new Vue({
el: "#app",
render: h => h(App),
// 使用路由器
router,
})

3、使用路由:
vue-router 提供了几个特殊标签来使用路由

<router-link> 会被解析为 A 标签,点击后切换路由
<router-view> 指定路由组件的呈现位置

App.vue
1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div>
<!-- 使用router-link标签进行route切换 -->
<router-link to="/home" active-class="active">Home</router-link>
<router-link to="/about" active-class="active">About</router-link>
<!-- 路由组件呈现位置 -->
<router-view></router-view>
</div>
</template>

<!-- ....... -->

4、编写路由组件:
一般组件:直接在另一个组件模板中写组件标签,一般放在 components 文件夹
路由组件:配置在路由器中,通过切换路由动态展示和销毁,一般放在 pages 文件夹

/pages/Home.vue
1
2
3
4
5
6
<template>
<div>
<h2>我是Home组件</h2>
</div>
</template>
<!-- .... -->
/pages/About.vue
1
2
3
4
5
6
<template>
<div>
<h2>我是About组件</h2>
</div>
</template>
<!-- .... -->

嵌套、多级路由

效果:

使用 children 属性配置子路由

/router/index.js
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
// 该文件用于创建路由器
import VueRouter from 'vue-router';
import About from '@/pages/About.vue';
import Home from '@/pages/Home.vue';
import Message from '@/pages/HomePages/Message.vue';
import News from '@/pages/HomePages/News.vue';

// 创建路由器
export default new VueRouter({
routes: [
// 一级路由
{
path: '/about',
component: About
},
{
path: '/home',
component: Home,
children: [
// 二级路由
{
// 多级路由不用再写斜杠
path: 'news',
component: News
},
{
path: 'message',
component: Message
}
],
},
]
});

修改 Home.vue 组件加上二级路由切换

/pages/Home.vue
1
2
3
4
5
6
7
8
9
10
<template>
<div>
<h2>我是Home组件</h2>
<router-link to="/home/message" active-class="active">Message</router-link>
<router-link to="/home/news" active-class="active">News</router-link>
<router-view></router-view>
</div>
</template>
<!-- .... -->

新建二级路由组件 Message.vue 和 News.vue

Message.vue 和 News.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- Message.vue -->
<template>
<div>
<h2>Home的二级路由Message</h2>
</div>
</template>
<!-- .... -->

<!-- News.vue -->
<template>
<div>
<h2>Home的二级路由News</h2>
</div>
</template>
<!-- .... -->

route的属性

获取route:组件中 this.$route,路由守卫中的 tofrom 参数

route上常用属性:

  1. fullPath 该路由的完整路径,带参数
  2. meta 一个对象,允许程序员自由地往里面加内容,可以在配置路由时就设置
  3. name 路由的名字
  4. params params参数
  5. path 路由路径
  6. query 查询字符串参数

路由query传参

通过 url 的 query(查询字符串)参数给子路由组件传参

使用:

/pages/HomePages/Message.vue
1
2
3
4
5
6
7
8
9
10
11
12
<!-- 模板字符串写法 -->
<router-link :to="`/home/message/detail?id=${item.id}&title=${item.title}`">{{ item.title }}</router-link>
<!-- 对象写法,推荐 -->
<router-link :to="{
path: '/home/message/detail',
query: {
id: item.id,
title: item.title
}
}">
{{ item.title }}</router-link>

子路由组件中通过 $route.query.<key> 获取 query 参数

/pages/HomePages/MessageDetail.vue
1
2
<h3>{{ $route.query.id }}</h3>
<h3>{{ $route.query.title }}</h3>

命名路由

给路由起名字,可以简化一些编码工作

/router/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
// 命名路由
name: 'Message',
path: 'message',
component: Message,
children: [
{
name: 'MessageDetail',
path: 'detail',
component: MessageDetail
}
]
}

使用 name 替代 path 配置,也能跳转路径

/pages/HomePages/Message.vue
1
2
3
4
5
6
7
8
9
<router-link :to="{
name: 'MessageDetail',
// path: '/home/message/detail',
query: {
id: item.id,
title: item.title
}
}">{{ item.title }}</router-link>

路由params传参

使用 params 传参需要在路由 path 配置中写上 url 参数(占位符)

/router/index.js
1
2
3
4
5
6
{
name: 'MessageDetail',
// 写上占位符
path: 'detail/:id/:title',
component: MessageDetail
}

传参:使用 params 传参,路径只能用 name 写法,不能写 path

/pages/HomePages/Message.vue
1
2
3
4
5
6
7
<router-link :to="{
name: 'MessageDetail',
params: { //传params参数
id: item.id,
title: item.title
}
}">{{ item.title }}</router-link>

获取参数: $route.params

/pages/HomePages/MessageDetail.vue
1
2
<h3>{{ $route.params.id }}</h3>
<h3>{{ $route.params.title }}</h3>

路由props配置

在路由配置中加上 props: true,该路由组件收到的所有 params 参数都会以 props 形式呈现

/router/index.js
1
2
3
4
5
6
7
8
9
10
{
name: 'MessageDetail',
path: 'detail/:id/:title',
component: MessageDetail,
// 写死数据,一般用不到
// props: {a:'1', b:'2'}
// 设置true,该路由组件收到的所有params参数都会以props形式呈现
props: true
}

接收 props

/pages/HomePages/MessageDetail.vue
1
2
3
4
5
export default {
name: 'MessageDetail',
// 接收props
props: ['id', 'title'],
}

props() 写成函数式,参数是该路由 $route ,可以自定义返回值,不再局限于之前只能传 params 参数

/router/index.js
1
2
3
4
5
6
7
8
9
10
11
12
{
name: 'MessageDetail',
path: 'detail/:id/:title',
component: MessageDetail,
// 解构赋值从$route中拿出params和query
props({params,query}){
return {
id: params.id,
title: query.title
}
}
}

replace属性

<router-link>replace 属性

作用:控制路由跳转时,操作浏览器历史记录的模式为 replace

操作浏览器历史记录有 push(默认) 和 replace 两种模式
(1) push 追加历史记录
(2) replace 替换当前记录,使浏览器不能通过后退返回之前的路径

1
2
<router-link to="/home" active-class="active" replace>Home</router-link>
<router-link to="/about" active-class="active" replace>About</router-link>

编程式路由

不使用 <router-link> 标签,通过调用 $router 上的方法,来控制路由的跳转

$router 原型上的 push()replace() 方法分别以pushreplace 两种模式跳转路由,都接收一个配置对象,内容和 to 属性中的一样

/pages/HomePages/Message.vue
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
<button @click="pushShow(item)">push跳转</button>
<button @click="replaceShow(item)">replace跳转</button>
<!-- ...... -->
<script>
// ......
methods: {
pushShow(item){
this.$router.push({
name: 'MessageDetail',
params: {
id: item.id,
title: item.title
}
})
},
replaceShow(item){
this.$router.replace({
name: 'MessageDetail',
params: {
id: item.id,
title: item.title
}
})
}
}
// ......
</script>

$router 的原型上还有其它方法
(1) back() 后退
(2) forward() 前进
(3) go() 前进或后退几个历史记录

在 vue-router 插件的某些版本,使用编程式路由时,相同路径跳转会报错,在路由配置文件中加上这段代码即可

/router/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 解决相同路径跳转报错的问题
//先保存一份VueRouter
let originPush = VueRouter.prototype.push;
let originReplace = VueRouter.prototype.replace;
//重写push|replace
//第一个参数:往哪里跳(传递哪些参数)
VueRouter.prototype.push = function(location,resolve,reject) {
if(resolve && reject) {
originPush.call(this,location,resolve,reject);
} else {
originPush.call(this,location,()=>{},()=>{});
}
}
VueRouter.prototype.replace = function(location,resolve,reject) {
if(resolve && reject) {
originReplace.call(this,location,resolve,reject);
} else {
originReplace.call(this,location,()=>{},()=>{});
}
}

缓存路由组件

切换路由,旧的路由组件会被销毁,在该组件中的用户输入等操作都会丢失

要想切换路由不销毁旧的组件,可以将 <router-view> 放入 <keep-alive> 标签中,include 属性指定要缓存的组件名(默认全缓存)

作用:让不展示的路由组件保持挂载,不被销毁

/pages/Home.vue
1
2
3
4
5
<router-link to="/home/message" active-class="active">Message</router-link>
<router-link to="/home/news" active-class="active">News</router-link>
<keep-alive include="News-">
<router-view></router-view>
</keep-alive>

两个新钩子

<keep-alive>能被其缓存路由组件添加了两个新的生命周期钩子

(1) activated() 路由组件被激活
(2) deactivated() 路由组件失活

作用:activated() 中开启定时器、发AJAX请求等,在 deactivated() 中关闭定时器等

路由守卫

作用:对路由进行权限控制

分类:全局守卫,独享守卫,组件内守卫

在前端业务中,经常有需要配合后端校验权限后才能打开的页面,如个人中心、订单记录等等,通过路由守卫就能在切换路由前,对权限进行校验,然后控制切不切换页面(放行),或跳转到某一页面(登陆页)

所有守卫本质都是函数,除了全局后置守卫没有第三个参数(next)之外,都有三个参数:
(1) to 要切换的路由对象
(2) from 切换前的路由对象
(3) next 一个函数,无参时切换to的路由,有参时切换到指定路由

三种守卫相互配合实现业务

全局守卫

全局路由守卫:监测所有路由的切换,只要切换路由,就会经过全局守卫的业务逻辑

分类:
(1) 全局前置守卫:在切换路由前触发的守卫
(2) 全局后置守卫:在成功切换路由后触发的守卫

配置全局守卫:在路由配置文件中,通过路由器上的两个方法配置全局守卫
(1) beforeEach(() => {}) 全局前置守卫
(2) afterEach(() => {}) 全局前置守卫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* ...... */
// 全局前置守卫
router.beforeEach((to, from, next) => {
console.log('切换路由前');
console.log(to);
console.log(from);
next();
})
// 全局后置守卫
router.afterEach((to, from) => {
console.log('切换路由后');
console.log(to);
console.log(from);
// 动态地切换网页标题
if (to.meta.title) {
document.title = to.meta.title;
}
})

独享守卫

独享路由守卫: beforeEnter() 只监测某个路由,要切换到该路由,才触发该守卫

注意:独享路由守卫没有后置,只在切换到该路由前触发

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
// 创建路由器
const router = new VueRouter({
routes: [
{
name: 'About',
path: '/about',
component: About,
meta: {
title: '关于'
},
// 独享路由守卫
beforeEnter(to, from, next) {
console.log('切换到关于路由前');
console.log(to);
console.log(from);
// 做一些业务,这里让一秒后再切换
setTimeout(() => {
next();
}, 1000);
},
},

/* ...... */

]
});

组件内守卫

组件内路由守卫:只在某一路由组件实例中生效的守卫,控制进入和离开该组件

分类:
(1) beforeRouteEnter() 通过路由规则 要进入该组件前 触发
(2) beforeRouteLeave() 通过路由规则 要离开该组件前 触发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export default {
name: 'Home-',
// 通过路由规则 要进入该组件前 触发
beforeRouteEnter(to, from, next){
console.log('要进入该组件');
console.log(to);
console.log(from);
next();
},
// 通过路由规则 要离开该组件前 触发
beforeRouteLeave(to, from, next){
console.log('要进入该组件');
console.log(to);
console.log(from);
next();
}
}

路由器两种工作模式

路由器有两种工作模式:
(1) hash 模式:url中带 # 号,如 localhost:8080/#/home
(2) history 模式:url中不带 # 号 如 localhost:8080/home

1、hash 模式:

  1. 对于 url 来说,# 号后面的内容都是 hash 值不会包含在 HTTP 请求的路径中,# 号后面的路径只是 vue 路由器工作所需
  2. 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法
  3. 兼容性较好,无需后端特地去处理路径问题

2、history 模式:

  1. url 样子较符合常理,也美观
  2. 项目上线后,需要后端去分辨前端路由和后端路由,返回不同的资源,解决 vue 这种单页应用程序切换路由后,刷新页面服务端404的问题,

mode 配置,指定路由器工作模式

1
2
3
4
5
const router = new VueRouter({
// mode: 'hash',
mode: 'history',
/* ...... */
})

NodeJS-Express 通过中间件 connect-history-api-fallback 自动处理路径问题

Element-UI

组件化编码催生出了许多优秀的UI组件库,导入即可使用

Element-UI 为例,vue2 使用 Element,vue3 用 Element Plus

使用组件库更多的是去看其提供的文档

安装: npm i element-ui -S

全部引入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import Vue from "vue";
import App from "./App.vue";
// 全部引入
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.config.productionTip = false;

// 使用ElementUI插件
Vue.use(ElementUI);

new Vue({
el: "#app",
render: h => h(App),
})

按需引入:

安装 babel-plugin-component

修改 babel.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset',
["@babel/preset-env", { "modules": false }]
],
plugins: [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}

然后就可以按需引入了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Vue from "vue";
import App from "./App.vue";
// 按需引入
import { Button,Row,DatePicker } from 'element-ui';

Vue.config.productionTip = false;

// 按需使用
Vue.use(Button);
Vue.use(Row);
Vue.use(DatePicker);

new Vue({
el: "#app",
render: h => h(App),
})

使用组件:看文档,cv使用组件标签

1
2
3
4
5
<el-button type="primary">主要按钮</el-button>
<el-date-picker
type="date"
placeholder="选择日期">
</el-date-picker>

项目上线

打包:npm run build 生成 dist 文件夹

将打包出的文件部署到服务端,交给后端去搞