1、前端核心分析
1.1 前端开发的核心变化
在 SSM 整合阶段,我们使用的是 JSP + JSTL + 原生 JS 的开发模式,存在以下痛点:
- DOM 操作繁琐:原生 JS 获取、修改 DOM 元素代码量大,易出错。
- 耦合度高:HTML 代码与 Java 代码(JSP)混合,维护困难。
- 渲染低效:每次数据变化都需要整体刷新页面,用户体验差。
- 缺乏组件化:页面复用困难,代码冗余。
1.2 Vue 解决了什么问题?
Vue 是一套渐进式 JavaScript 框架,核心解决了前端渲染与数据交互问题:
- 数据驱动视图:只操作数据,DOM 操作由框架自动完成(Virtual DOM)。
- 组件化开发:将页面拆分为独立的组件(按钮、表格、弹窗等),复用性极强。
- 轻量级:体积小(约 33KB),性能优,上手门槛低。
- 双向数据绑定:表单数据与模型自动同步,无需手动取值。
1.3 Vue 核心思想
- MVVM 架构:Model(数据)↔ ViewModel(监听者)↔ View(视图)。
- 声明式编程:只需要告诉计算机 "做什么",不需要关心 "怎么做"。
2、前端发展史
2.1 前端进化史(三个阶段)
| 阶段 | 时代特征 | 核心技术 | 开发模式 | 代表项目 |
|---|---|---|---|---|
| 第一阶段 | 静态网页时代 | HTML + CSS | 后端渲染(JSP/PHP) | 传统 SSM 项目 |
| 第二阶段 | 异步交互时代 | jQuery + AJAX | 前后端不分离(局部刷新) | 很多传统管理系统 |
| 第三阶段 | 组件化 / 工程化时代 | Vue/React/Angular | 前后端分离(RESTful API) | 电商、后台管理系统 |
2.2 为什么学 Vue?
- 市场占有率高:国内主流招聘岗位,Vue 是必备技能。
- 生态完善:Vue Router(路由)、Vuex/Pinia(状态管理)、Vue CLI(脚手架)。
- 易学易用:官方文档中文完善,API 设计人性化。
- 结合 SSM 升级:后端 SSM 做接口,前端 Vue 做渲染,是目前企业最主流的开发模式。
3、第一个 Vue 程序
3.1 环境引入(CDN 方式,入门首选)
无需安装 Node.js,直接在 HTML 中引入 CDN 链接即可使用。
创建文件:src/main/webapp/vue_demo/01.hello.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>第一个 Vue 程序</title>
<!-- 1. 引入 Vue CDN -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<!-- 2. 挂载点 -->
<div id="app">
<!-- 3. 插值表达式,获取数据 -->
<h1>{{ message }}</h1>
</div>
<script>
// 4. 创建 Vue 实例
new Vue({
el: "#app", // 挂载点,控制 id 为 app 的区域
data: { // 数据模型
message: "Hello, Vue!"
}
});
</script>
</body>
</html>
3.2 运行效果
启动服务器,访问该页面,将看到 Hello, Vue! 红色大字。
3.3 核心概念
el: "#app":挂载边界,Vue 只管辖该元素内部的代码,外部不受影响。data:存放页面需要的数据,数据变化会自动反映到视图。{``{ }}:插值表达式,用于输出 data 中的数据到页面。
4、Vue 基本语法
4.1 插值表达式(Mustache 语法)
用于输出文本,支持简单的运算。
html
<div id="app">
<!-- 1. 基本输出 -->
<p>{{ msg }}</p>
<!-- 2. 简单运算 -->
<p>{{ number + 1 }}</p>
<!-- 3. 字符串拼接 -->
<p>{{ 'Hello ' + name }}</p>
<!-- 4. 三元运算 -->
<p>{{ flag ? '成功' : '失败' }}</p>
</div>
<script>
new Vue({
el: "#app",
data: {
msg: "Vue 语法",
number: 10,
name: "Vue",
flag: true
}
});
</script>
4.2 指令(Directives)
指令是 Vue 模板中最核心的功能,带有 v- 前缀。
常用指令示例
html
<div id="app">
<!-- v-text:输出文本,不会解析标签 -->
<div v-text="msg"></div>
<!-- v-html:输出 HTML 代码(注意 XSS 攻击) -->
<div v-html="htmlStr"></div>
<!-- v-show:根据真假切换 display 属性(隐藏/显示) -->
<div v-show="isShow">显示/隐藏</div>
<!-- v-if:根据真假销毁/重建元素(更高的切换开销) -->
<div v-if="isShow">条件渲染</div>
</div>
5、Vue 绑定事件
5.1 v-on 指令
用于绑定 DOM 事件,如点击、鼠标移入等。简写语法 :@ 替代 v-on:
示例(计数器)
html
<div id="app">
<h3>计数:{{ count }}</h3>
<!-- 完整写法:v-on:click -->
<button v-on:click="increment">+1</button>
<!-- 简写写法:@click -->
<button @click="decrement">-1</button>
<!-- 直接执行代码,无需调用方法 -->
<button @click="count = 0">重置</button>
</div>
<script>
new Vue({
el: "#app",
data: {
count: 0
},
methods: { // 定义事件处理方法
increment() {
this.count++; // 修改 data 数据
},
decrement() {
this.count--;
}
}
});
</script>
5.2 事件修饰符
处理事件冒泡、默认行为等:
html
<!-- 阻止事件冒泡 -->
<div @click="outerClick">
<button @click.stop="innerClick">内部按钮</button>
</div>
<!-- 阻止默认行为(如 a 标签跳转) -->
<a href="http://www.baidu.com" @click.prevent="goTo">百度</a>
6、Vue 双向绑定
6.1 核心指令 v-model
原理:在表单元素(input/select/textarea)上创建双向数据绑定。
- 视图变 ➡ 数据变
- 数据变 ➡ 视图变
6.2 基础示例(表单输入)
html
<div id="app">
<!-- 双向绑定:input 输入框与 message 同步 -->
<input type="text" v-model="message">
<p>你输入的内容是:{{ message }}</p>
<!-- 单选按钮 -->
<input type="radio" value="男" v-model="gender">男
<input type="radio" value="女" v-model="gender">女
<p>选中的性别:{{ gender }}</p>
</div>
<script>
new Vue({
el: "#app",
data: {
message: "",
gender: ""
}
});
</script>
6.3 v-model 修饰符
.trim:去除首尾空格.number:转为数字类型.lazy:失去焦点 / 回车时才更新(而非实时同步)
html
<input type="text" v-model.trim="name">
<input type="text" v-model.number="age">
7、Vue 组件讲解
7.1 组件核心概念
组件(Component)是 Vue 实现页面复用的最小单元。
- 全局组件:在所有 Vue 实例中都能使用。
- 局部组件:仅在当前 Vue 实例挂载的区域内使用。
7.2 全局组件示例(App 标题栏)
html
<div id="app">
<!-- 使用组件 -->
<my-nav></my-nav>
<my-nav></my-nav>
</div>
<script>
// 1. 注册全局组件
Vue.component("MyNav", {
// 模板:组件的 HTML 结构(必须有一个根容器)
template: `
<div class="nav">
<h3>这是一个导航组件</h3>
</div>
`
});
// 2. 挂载 Vue
new Vue({ el: "#app" });
</script>
7.3 局部组件 + 传值(Props)
组件之间的数据传递,子组件通过 props 接收父组件数据。
html
<div id="app">
<!-- 父组件向子组件传值:title="书籍管理" -->
<book-item title="Java 编程思想" price="79"></book-item>
<book-item title="Vue 实战" price="69"></book-item>
</div>
<script>
// 1. 定义子组件
let BookItem = {
// props: 接收父组件传递的属性(需声明类型)
props: {
title: {type: String, required: true},
price: {type: Number, default: 0}
},
// 模板中使用 props 数据
template: `
<div class="book">
<h4>{{ title }}</h4>
<p>价格:{{ price }} 元</p>
</div>
`
};
// 2. 挂载 Vue,并注册局部组件
new Vue({
el: "#app",
components: {
// 标签名: 组件对象
BookItem: BookItem
}
});
</script>
7.4 组件生命周期(简述)
组件从创建到销毁的过程,核心钩子函数:
created():实例创建完成,DOM 未生成(可发起 AJAX)。mounted():DOM 挂载完成(真实 DOM 操作在这里做)。updated():数据更新导致 DOM 更新。
8、Axios 异步通信
8.1 核心定义
Axios 是 Promise 风格的 HTTP 客户端,是 Vue 官方推荐的异步请求库,用于前端向后端 SSM 接口发起请求、获取 JSON 数据,实现前后端分离。
8.2 核心特性
- 支持 Promise API,链式调用更优雅
- 自动转换 JSON 数据,无需手动解析
- 拦截请求 / 响应,统一处理异常、添加请求头
- 兼容浏览器和 Node.js,跨平台使用
8.3 基础使用(CDN 引入)
html
<!-- 引入 Axios -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<div id="app">
<button @click="getBookList">获取书籍列表</button>
<ul>
<li v-for="book in books" :key="book.id">{{ book.bookName }}</li>
</ul>
</div>
<script>
new Vue({
el: "#app",
data: {
books: []
},
methods: {
// 发起 GET 请求,调用 SSM 后端接口
async getBookList() {
try {
const res = await axios.get("http://localhost:8080/book/all");
this.books = res.data; // 直接获取响应数据
} catch (err) {
console.error("请求失败:", err);
}
}
}
});
</script>
8.4 常用请求方式
javascript
// GET 请求
axios.get("/user", { params: { id: 1 } });
// POST 请求(提交 JSON 数据)
axios.post("/user", { username: "zhangsan", password: "123456" });
// 通用请求配置
axios({
method: "post",
url: "/book/add",
data: book,
headers: { "Content-Type": "application/json" }
});
9、计算属性
9.1 核心定义
计算属性(computed)是 Vue 中基于依赖缓存的属性,用于处理复杂的逻辑计算,避免在模板中编写大量表达式,提升性能和可维护性。
9.2 基础示例(总价计算)
html
<div id="app">
<p>商品单价:{{ price }}</p>
<p>购买数量:<input type="number" v-model.number="count"></p>
<p>商品总价:{{ totalPrice }}</p>
</div>
<script>
new Vue({
el: "#app",
data: {
price: 99,
count: 1
},
computed: {
// 计算属性:自动监听依赖(price/count)变化,重新计算
totalPrice() {
return this.price * this.count;
}
}
});
</script>
9.3 计算属性 vs 方法
| 特性 | 计算属性 | 方法 |
|---|---|---|
| 缓存 | 有,依赖不变时直接返回缓存值 | 无,每次调用都重新执行 |
| 调用 | 直接作为属性使用(totalPrice) |
需加括号调用(getTotal()) |
| 适用场景 | 复杂计算、需要缓存的场景 | 事件触发、无缓存需求的场景 |
9.4 计算属性的 setter(双向绑定)
javascript
computed: {
fullName: {
get() {
return `${this.firstName} ${this.lastName}`;
},
set(val) {
const names = val.split(" ");
this.firstName = names[0];
this.lastName = names[1];
}
}
}
10、插槽 slot
10.1 核心定义
插槽(slot)是 Vue 实现组件内容分发的核心机制,让组件的 HTML 结构可自定义,提升组件的复用性和灵活性。
10.2 基础使用(匿名插槽)
html
<!-- 定义组件:带插槽 -->
<template id="my-dialog">
<div class="dialog">
<div class="dialog-header">
<h3>弹窗标题</h3>
</div>
<div class="dialog-body">
<!-- 匿名插槽:父组件可插入任意内容 -->
<slot></slot>
</div>
</div>
</template>
<div id="app">
<!-- 使用组件:在插槽位置插入自定义内容 -->
<my-dialog>
<p>这是自定义的弹窗内容</p>
<button>确认</button>
</my-dialog>
</div>
<script>
Vue.component("MyDialog", {
template: "#my-dialog"
});
new Vue({ el: "#app" });
</script>
10.3 具名插槽(v-slot)
给插槽命名,实现多位置内容分发,Vue 2.6+ 推荐语法:
html
<!-- 组件模板 -->
<div class="layout">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot> <!-- 匿名插槽 -->
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
<!-- 使用组件 -->
<my-layout>
<template v-slot:header>
<h1>页面头部</h1>
</template>
<p>页面主体内容</p>
<template v-slot:footer>
<p>页面底部</p>
</template>
</my-layout>
10.4 作用域插槽
让插槽内容能够访问子组件的数据,实现数据双向传递:
html
<!-- 子组件 -->
<ul>
<li v-for="item in list" :key="item.id">
<slot :item="item"></slot>
</li>
</ul>
<!-- 父组件 -->
<my-list :list="books">
<template v-slot="slotProps">
<span>{{ slotProps.item.bookName }}</span>
</template>
</my-list>
11、自定义事件内容分发
11.1 核心定义
自定义事件是 Vue 实现子组件向父组件传值 的核心机制:子组件通过 $emit 触发事件,父组件通过 v-on 监听事件,实现组件间通信。
11.2 基础示例(子组件触发事件)
html
<!-- 子组件:计数器 -->
<template id="counter">
<div>
<button @click="increment">+1</button>
<p>当前计数:{{ count }}</p>
</div>
</template>
<script>
Vue.component("Counter", {
template: "#counter",
data() {
return { count: 0 };
},
methods: {
increment() {
this.count++;
// 触发自定义事件,向父组件传递数据
this.$emit("count-change", this.count);
}
}
});
</script>
<!-- 父组件:监听事件 -->
<div id="app">
<counter @count-change="handleCountChange"></counter>
<p>父组件收到的计数:{{ currentCount }}</p>
</div>
<script>
new Vue({
el: "#app",
data: { currentCount: 0 },
methods: {
handleCountChange(val) {
this.currentCount = val;
}
}
});
</script>
11.3 事件修饰符 .native
给组件绑定原生 DOM 事件时使用,否则事件不会触发:
html
<my-button @click.native="handleClick"></my-button>
12、第一个 vue-cli 程序
12.1 核心定义
Vue CLI 是 Vue 官方提供的项目脚手架工具,用于快速搭建标准化的 Vue 项目,集成 webpack、babel、热更新等工具,无需手动配置环境。
12.2 环境准备
- 安装 Node.js(版本 ≥ 14.x)
- 全局安装 Vue CLI:
bash
npm install -g @vue/cli
# 验证安装
vue --version
12.3 创建项目
bash
# 交互式创建项目
vue create ssm-vue-demo
# 选择预设(推荐默认:babel + eslint)
# 等待项目依赖安装完成
12.4 项目结构
plaintext
ssm-vue-demo
├── public/ # 静态资源
├── src/
│ ├── assets/ # 项目资源(css、img)
│ ├── components/ # 组件
│ ├── views/ # 页面组件
│ ├── router/ # 路由配置
│ ├── App.vue # 根组件
│ └── main.js # 入口文件
├── package.json # 依赖配置
└── vue.config.js # Vue CLI 配置
12.5 启动项目
bash
cd ssm-vue-demo
npm run serve
# 访问 http://localhost:8080 即可看到项目
13、webpack 学习使用
13.1 核心定义
webpack 是静态模块打包器,是 Vue CLI 的底层核心工具,用于将项目中的 JS、CSS、图片等资源打包成优化后的静态文件,实现模块化开发。
13.2 核心概念
- 入口(entry):打包的起点文件
- 出口(output):打包后的文件输出位置
- loader:处理非 JS 文件(如 CSS、图片),转换为 webpack 可识别的模块
- 插件(plugin):执行更广泛的任务(如打包优化、资源管理)
- 模式(mode):开发模式(development)/ 生产模式(production)
13.3 基础配置示例(webpack.config.js)
javascript
const path = require("path");
module.exports = {
entry: "./src/main.js", // 入口
output: { // 出口
path: path.resolve(__dirname, "dist"),
filename: "bundle.js"
},
module: { // loader
rules: [
{ test: /\.css$/, use: ["style-loader", "css-loader"] },
{ test: /\.(png|jpg)$/, use: ["file-loader"] }
]
},
plugins: [ // 插件
new HtmlWebpackPlugin({ template: "./public/index.html" })
],
mode: "development"
};
13.4 核心作用
- 模块化开发,支持 ES6+ 语法
- 代码压缩、混淆,提升性能
- 处理资源依赖,自动打包
- 热更新,提升开发效率
14、vue-router 路由
14.1 核心定义
Vue Router 是 Vue 官方的路由管理器,用于实现单页应用(SPA)的页面跳转,让不同的 URL 对应不同的组件,无需刷新页面切换视图。
14.2 基础使用
- 安装依赖:
bash
npm install vue-router@3
- 路由配置(router/index.js)
javascript
import Vue from "vue";
import VueRouter from "vue-router";
import BookList from "../views/BookList.vue";
import AddBook from "../views/AddBook.vue";
Vue.use(VueRouter);
const routes = [
{ path: "/", redirect: "/book/list" },
{ path: "/book/list", component: BookList },
{ path: "/book/add", component: AddBook }
];
const router = new VueRouter({ routes });
export default router;
- 根组件(App.vue)
html
<template>
<div id="app">
<!-- 路由导航 -->
<router-link to="/book/list">书籍列表</router-link>
<router-link to="/book/add">添加书籍</router-link>
<!-- 路由视图:渲染匹配的组件 -->
<router-view></router-view>
</div>
</template>
- 入口文件(main.js)
javascript
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
new Vue({
router,
render: h => h(App)
}).$mount("#app");
14.3 路由传参
- params 传参 :
/user/:id,通过$route.params.id获取 - query 传参 :
/user?id=1,通过$route.query.id获取
15、vue + elementUI
15.1 核心定义
Element UI 是 基于 Vue 2 的桌面端组件库,提供了丰富的开箱即用的组件(表格、表单、弹窗、导航等),用于快速搭建后台管理系统,大幅提升开发效率。
15.2 安装与引入
bash
npm install element-ui
入口文件(main.js)全局引入:
javascript
import Vue from "vue";
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
Vue.use(ElementUI);
15.3 基础示例(表格组件)
html
<template>
<el-container>
<el-header>书籍管理系统</el-header>
<el-main>
<!-- 表格组件 -->
<el-table :data="tableData" border stripe>
<el-table-column prop="id" label="书籍ID"></el-table-column>
<el-table-column prop="bookName" label="书名"></el-table-column>
<el-table-column prop="author" label="作者"></el-table-column>
<el-table-column prop="price" label="价格"></el-table-column>
</el-table>
</el-main>
</el-container>
</template>
<script>
export default {
data() {
return {
tableData: []
};
},
async mounted() {
// 调用 Axios 获取数据
const res = await this.$axios.get("/book/all");
this.tableData = res.data;
}
};
</script>
15.4 核心优势
- 组件丰富,覆盖后台管理全场景
- 样式美观,交互体验好
- 文档完善,中文支持好
- 与 Vue 深度集成,开发效率高
16、路由嵌套
16.1 核心定义
路由嵌套(Nested Routes)用于实现页面内的子路由跳转,让一个父路由下包含多个子路由,适配复杂的页面结构(如后台管理系统的侧边栏 + 主内容区)。
16.2 核心原理
- 父路由组件中通过
<router-view>渲染子路由 - 路由配置中通过
children属性定义子路由 - 子路由的
path无需加/,会自动继承父路由路径
16.3 完整实现示例
1. 路由配置(router/index.js)
javascript
import Vue from 'vue'
import VueRouter from 'vue-router'
import Layout from '@/views/Layout.vue'
import BookList from '@/views/book/BookList.vue'
import AddBook from '@/views/book/AddBook.vue'
import UserList from '@/views/user/UserList.vue'
Vue.use(VueRouter)
const routes = [
{
// 父路由:后台布局页
path: '/admin',
component: Layout,
// 子路由:嵌套在 Layout 中
children: [
{
// 子路由路径:/admin/book/list
path: 'book/list',
component: BookList,
meta: { title: '书籍列表' }
},
{
path: 'book/add',
component: AddBook,
meta: { title: '添加书籍' }
},
{
path: 'user/list',
component: UserList,
meta: { title: '用户列表' }
},
// 子路由默认重定向
{ path: '', redirect: '/admin/book/list' }
]
},
// 根路由重定向
{ path: '/', redirect: '/admin' }
]
const router = new VueRouter({ routes })
export default router
2. 父路由组件(Layout.vue)
vue
<template>
<div class="layout">
<!-- 侧边栏导航 -->
<aside class="sidebar">
<router-link to="/admin/book/list">书籍管理</router-link>
<router-link to="/admin/user/list">用户管理</router-link>
</aside>
<!-- 主内容区:渲染子路由 -->
<main class="main">
<router-view></router-view>
</main>
</div>
</template>
16.4 核心要点
- 子路由的
<router-view>必须写在父路由组件内 - 子路由
path以/开头会被视为根路径,不会继承父路径 - 可通过
meta给路由添加自定义信息(如标题、权限标识)
17、参数传递及重定向
17.1 路由参数传递的 3 种方式
1. params 传参(RESTful 风格)
- 路由配置中定义参数占位符
:id - 参数会被拼接到 URL 中,刷新页面不丢失
- 适合资源类请求(如查询书籍详情)
路由配置:
javascript
{
path: '/admin/book/detail/:id',
component: BookDetail
}
跳转与取值:
vue
<!-- 跳转 -->
<router-link :to="`/admin/book/detail/${book.id}`">详情</router-link>
<!-- 编程式导航 -->
this.$router.push(`/admin/book/detail/${id}`)
<!-- 取值 -->
<p>书籍ID:{{ $route.params.id }}</p>
2. query 传参(传统 URL 参数)
- 参数以
?key=value形式拼接在 URL 后 - 适合非资源类、可选参数的场景
- 刷新页面不丢失
跳转与取值:
vue
<!-- 跳转 -->
<router-link :to="{ path: '/admin/book/list', query: { name: 'Vue' } }">搜索</router-link>
<!-- 编程式导航 -->
this.$router.push({ path: '/admin/book/list', query: { name: 'Vue' } })
<!-- 取值 -->
<p>搜索关键词:{{ $route.query.name }}</p>
3. props 传参(解耦组件)
- 将路由参数映射为组件的
props,让组件不依赖$route - 提升组件复用性,便于单元测试
路由配置:
javascript
{
path: '/admin/book/detail/:id',
component: BookDetail,
// 开启 props 映射,params 参数会自动注入组件 props
props: true
}
组件内使用:
vue
<script>
export default {
// 声明 props,接收路由参数
props: ['id'],
mounted() {
console.log('书籍ID:', this.id)
}
}
</script>
17.2 路由重定向
1. 路由配置中重定向
javascript
// 方式1:直接重定向到指定路径
{ path: '/', redirect: '/admin' }
// 方式2:重定向到命名路由
{ path: '/', redirect: { name: 'BookList' } }
// 方式3:动态重定向(根据条件返回目标路径)
{ path: '/', redirect: to => {
return localStorage.getItem('token') ? '/admin' : '/login'
}}
2. 编程式重定向
javascript
// 方式1:push 跳转(可回退)
this.$router.push('/admin')
// 方式2:replace 替换(不可回退,适合登录后跳转)
this.$router.replace('/admin')
// 方式3:go 回退/前进
this.$router.go(-1) // 回退一页
17.3 命名路由
给路由添加 name 属性,通过名称跳转,避免硬编码路径:
javascript
{
path: '/admin/book/list',
name: 'BookList',
component: BookList
}
// 跳转
this.$router.push({ name: 'BookList' })
18、404 和路由钩子
18.1 404 页面处理
1. 配置 404 路由
- 必须放在路由配置的最后一项,否则会拦截所有路由
- 使用
*通配符匹配所有未匹配的路径
javascript
import NotFound from '@/views/NotFound.vue'
const routes = [
// ... 其他路由配置
// 404 路由,必须放在最后
{ path: '*', component: NotFound }
]
2. 404 页面组件(NotFound.vue)
vue
<template>
<div class="not-found">
<h1>404 - 页面不存在</h1>
<p>你访问的页面不存在或已删除</p>
<router-link to="/">返回首页</router-link>
</div>
</template>
18.2 路由钩子(导航守卫)
路由钩子用于拦截路由跳转,实现权限校验、登录判断、全局 loading 等功能,分为 3 类:
1. 全局守卫
- 作用于所有路由,是项目权限控制的核心
- 包括
beforeEach(前置守卫)、afterEach(后置守卫)
javascript
router.beforeEach((to, from, next) => {
// to:目标路由对象
// from:当前路由对象
// next:放行函数,必须调用
const token = localStorage.getItem('token')
// 登录页直接放行
if (to.path === '/login') {
next()
} else {
// 其他页面需校验 token
if (token) {
next()
} else {
next('/login')
}
}
})
// 后置守卫:路由跳转完成后执行
router.afterEach((to, from) => {
// 关闭全局 loading、修改页面标题等
document.title = to.meta.title || 'SSM-VUE 管理系统'
})
2. 路由独享守卫
- 写在单个路由配置中,仅作用于当前路由
- 适合单个路由的权限校验
javascript
{
path: '/admin/user/list',
component: UserList,
// 路由独享守卫
beforeEnter: (to, from, next) => {
const role = localStorage.getItem('role')
if (role === 'admin') {
next()
} else {
next('/403')
}
}
}
3. 组件内守卫
- 写在组件内部,仅作用于当前组件的路由
- 包括
beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
vue
<script>
export default {
// 进入组件前调用(此时组件实例未创建,无法访问 this)
beforeRouteEnter(to, from, next) {
next(vm => {
// 通过 vm 访问组件实例
console.log('进入组件:', vm)
})
},
// 路由更新时调用(如 params 变化)
beforeRouteUpdate(to, from, next) {
next()
},
// 离开组件前调用(可访问 this)
beforeRouteLeave(to, from, next) {
if (confirm('确定要离开当前页面吗?')) {
next()
} else {
next(false)
}
}
}
</script>
18.3 完整的路由守卫执行顺序
- 全局
beforeEach - 路由独享
beforeEnter - 组件内
beforeRouteEnter - 全局
beforeResolve - 全局
afterEach - 组件内
beforeRouteUpdate(路由更新时) - 组件内
beforeRouteLeave(离开时)