🎯 Vuex 核心概念与数据流
Vuex 是专为 Vue 开发的集中式状态管理库,它提供了一个集中式的状态管理机制,用于管理 Vue 应用中的所有组件的共享状态,适用于中大型 Vue 应用。
核心思想
将组件共享状态抽离为独立状态树,通过定义 getters、mutations、actions 来操作状态。
核心概念
| 概念 | 作用 | 特点 |
|---|---|---|
| state | 应用的数据源 | 唯一的状态树 |
| getters | 对 state 数据进行计算/过滤 | 类似于计算属性,缓存结果 |
| mutations | 修改 state 的唯一方式 | 同步操作,通过 commit 调用 |
| actions | 处理异步或批量同步操作 | 最终通过 mutations 改变 state |
单向数据流
在 Vuex 中,数据流的流向是单向的,这种机制使得数据的流动更加清晰,同时也更容易进行调试和维护。
state → 组件 → actions/mutations → state
辅助函数
mapState: 映射 state 到组件计算属性mapGetters: 映射 getters 到组件计算属性mapActions: 映射 actions 到组件方法mapMutations: 映射 mutations 到组件方法
高级特性
- 模块化状态管理: 拆分大型状态树为多个模块
- 插件机制: 扩展 Vuex 功能(如持久化存储)
这些高级特性能够进一步提高我们的开发效率。
🔄 Vue Router 核心原理
Vue Router 是 Vue 官方路由管理器,通过监听 URL 变化实现单页应用路由控制。
Vue Router 是实现 Vue 单页应用路由控制的核心组件之一,它通过路由匹配、路由模式、路由导航、路由组件等多个方面实现了完整的路由控制逻辑,为开发者提供了强大的路由控制能力。
四大核心原理
1. 路由匹配
- 定义路由规则匹配 URL 路径
- 支持路径、参数、查询参数
- 支持嵌套路由和命名路由
2. 路由模式
| 模式 | 实现方式 | 特点 |
|---|---|---|
| hash 模式 | 监听 URL 的 hash 部分来进行路由控制 | 兼容性好,无需后端配置 |
| history 模式 | 借助 HTML5 History API,通过修改浏览器历史记录来进行路由控制 | URL 更美观,需要后端配置 |
3. 路由导航
- 导航钩子监听路由变化,实现路由拦截、身份验证等功能
- 支持全局和组件内守卫,可以在路由跳转前、跳转后、路由更新等不同阶段执行相应的逻辑
4. 路由组件
- 动态加载组件提升性能
- 支持路由懒加载
- 支持路由元信息
⚓ Vue Router 导航钩子全解析
导航钩子在路由解析流程中按顺序触发,构成完整的路由控制机制。
完整导航流程
- 导航被触发
当路由发生变化时,导航开始。
- 组件离开守卫
beforeRouteLeave:离开当前组件时调用
可以访问 this,可以用来进行页面数据的保存或弹出提示等操作,通常用于表单未保存提示。
beforeRouteLeave(to, from, next) {
// 保存数据或提示用户
next();
}
- 全局前置守卫
beforeEach:每次导航都会触发
在每次路由跳转之前执行,可以用来进行用户身份验证、路由拦截等操作。
router.beforeEach((to, from, next) => {
// 身份验证、路由拦截
next();
});
- 组件更新守卫
beforeRouteUpdate:路由改变但组件复用时调用
可访问 this,用于响应路由参数变化。
beforeRouteUpdate(to, from, next) {
// 响应路由参数变化
next();
}
- 路由独享守卫
beforeEnter:针对具体路由设置
在进入路由之前执行,与 beforeEach 的区别是它可以针对某个具体路由进行设置。
{
path: '/user/:id',
component: User,
beforeEnter: (to, from, next) => {
// 路由特定处理
next();
}
}
-
解析异步路由组件
-
组件进入守卫
beforeRouteEnter:进入目标组件前调用
不能访问 this(组件实例还未创建),但可以通过 next 的回调访问。
beforeRouteEnter(to, from, next) {
next(vm => {
// 通过回调访问组件实例
});
}
- 全局解析守卫
beforeResolve:所有守卫和异步组件解析后执行
可以用于数据预取或权限的最终检查,或者确保异步组件加载完成。
// 权限最终检查
router.beforeResolve((to, from, next) => {
if (to.meta.requiresAdmin) {
return store.dispatch('checkAdminRights')
.then(hasRights => {
if (hasRights) next()
else next('/unauthorized')
})
}
next()
})
// 确保异步组件加载完成
router.beforeResolve((to, from, next) => {
const matched = to.matched
const preloadPromises = matched
.map(record => record.components.default)
.filter(component => typeof component === 'function')
.map(asyncComponent => {
return asyncComponent().catch(() => null)
})
Promise.all(preloadPromises)
.then(() => next())
.catch(error => {
console.error('组件加载失败:', error)
next('/error')
})
})
-
导航被确认
-
全局后置钩子
afterEach:导航完成后调用
没有 next 函数,可以用来进行路由跳转后的操作,比如页面滚动、统计PV(Page View页面浏览量)等操作。
router.afterEach((to, from) => {
// 页面滚动、PV 统计
});
-
触发 DOM 更新
-
执行 beforeRouteEnter 的 next 回调:可访问组件实例
重要规则
- 除
afterEach外,每个守卫都必须调用next()才能继续往下导航 - 守卫可以返回
false取消导航,或重定向到其他路由
总结
这些导航钩子提供了灵活的路由跳转控制机制,可以方便地实现各种复杂的路由跳转需求。 Vue Router 还提供了一些其他的导航钩子和高级特性,比如路由元信息、动态路由、命名路由等,可以进一步提高开发效率和应用的可维护性。
🧭 Vue Router hash 模式实现锚点的四种方式
方式一:监听 hash 变化并手动滚动
// router/index.js
const router = new VueRouter({
mode: 'hash',
routes: [/* 路由配置 */]
})
// 设置目标 URL 的 hash 部分为锚点的名称
this.$router.push({ path: '/yourpath', hash: '#youranchor' })
// 目标组件
<script setup>
import { useRoute, onMounted } from 'vue-router'
const route = useRoute()
onMounted(() => {
const anchor = document.getElementById(route.hash)
if (anchor) {
anchor.scrollIntoView()
}
})
</script>
方式二:编程式导航
<template>
<div>
<button @click="scrollToSection('section1')">Go to Section 1</button>
<button @click="scrollToSection('section2')">Go to Section 2</button>
<div id="section1">Section 1 Content</div>
<div id="section2">Section 2 Content</div>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
const scrollToSection = (id) => {
// 方法1:使用 router.push
router.push({ hash: `#${id}` })
// 方法2:直接修改 URL(不推荐,可能和 Vue Router 冲突)
window.location.hash = '#' + id
}
</script>
方式三:使用原生锚点
<template>
<div>
<!-- 方式一:直接使用 a 标签 -->
<a href="#section1">Go to Section 1</a>
<!-- 方式二:Vue Router 链接添加 hash -->
<router-link :to="{ path: $route.path, hash: '#section1' }">
Go to Section 1
</router-link>
</div>
</template>
方式四:使用 Vue Router 的 scrollBehavior(推荐)
// router/index.js
import { createRouter, createWebHashHistory } from 'vue-router'
const router = createRouter({
history: createWebHashHistory(),
routes: [/* 路由配置 */],
scrollBehavior(to, from, savedPosition) {
// 在 Vue Router 4 中,hash 模式下的 scrollBehavior 默认不工作,需要手动实现
if (to.hash) {
return {
el: to.hash,
behavior: 'smooth', // 平滑滚动
top: 20 // 偏移量
}
}
return { top: 0 }
}
})
<template>
<div>
<nav>
<router-link to="#section1">Section 1</router-link>
<router-link to="#section2">Section 2</router-link>
<router-link to="#section3">Section 3</router-link>
</nav>
<div style="height: 100vh">首页内容</div>
<section id="section1">
<h2>Section 1</h2>
<div>内容...</div>
</section>
<section id="section2">
<h2>Section 2</h2>
<div>内容...</div>
</section>
<section id="section3">
<h2>Section 3</h2>
<div>内容...</div>
</section>
</div>
</template>
🚀 Vue Router history 模式上线注意事项
Vue Router 的 history 模式相比于默认的 Hash 模式来说,能够更好地模拟传统的多页面应用的 URL 地址,让用户体验更加自然。
1. 后端配置
必须配置后端服务器,将所有路由请求指向入口文件(index.html),避免刷新 404。
2. 安全性
- 暴露服务器文件路径,需仔细检查配置
- 防止恶意请求导致安全问题
3. 兼容性
需要浏览器支持 HTML5 History API,旧浏览器可能存在兼容性问题。
4. 打包发布配置
在使用 Webpack 等工具打包发布时,需要配置正确的 publicPath,保证 HTML 中引用的资源路径正确。
Vite 配置(对应 Webpack 的 publicPath)
// vite.config.js
export default defineConfig({
base: '/my-app/', // 部署基础路径
plugins: [vue()]
})
多环境配置
// vite.config.js
export default defineConfig(({ mode }) => {
const base = {
development: '/',
staging: '/staging/',
production: '/my-app/'
}[mode] || '/'
return {
base,
plugins: [vue()],
}
})
环境变量配置
# .env.production
VITE_APP_BASE_URL=/my-app/
// vite.config.js
export default defineConfig({
base: process.env.VITE_APP_BASE_URL || '/',
})
与 Vue Router 配合
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
const base = import.meta.env.BASE_URL || '/' // 动态获取 base 路径
const router = createRouter({
history: createWebHistory(base),
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About },
{ path: '/user/:id', component: User }
// 所有子路由都会自动基于这个 base
]
})
❌ history 模式刷新 404 问题解析
原因
浏览器刷新页面时向服务器发送 GET 请求,但服务器没有对应的资源文件,因为在 history 模式下,所有路由都是在前端路由中实现的。
解决方案
配置服务器将所有请求指向 index.html,由前端路由处理。
Nginx 配置示例
server {
listen 80;
server_name yourdomain.com;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html; # 关键配置
}
}
📝 总结
本文详细复习了 Vue 生态中两个核心工具:
- Vuex:集中式状态管理,通过 state、getters、mutations、actions 实现单向数据流
- Vue Router:路由管理核心原理,导航钩子全流程,hash/history 模式应用场景
重点掌握:
- Vuex 的单向数据流和模块化使用
- Vue Router 导航钩子的执行顺序和应用
- hash/history 模式的区别和部署注意事项
- history 模式刷新 404 问题的解决方案
这些知识是中高级 Vue 开发者必须掌握的核心内容,理解并熟练应用它们将极大提升你的 Vue 项目开发能力。