本文用最直观的电商购物车案例,带你20分钟掌握Vuex核心用法!
一、为什么需要Vuex?
1. 组件通信困境
- 多级组件传参繁琐(超过3层)
- 兄弟组件无法直接通信
- 多个组件共享状态时管理困难
2. Vuex的作用
- 集中管理所有组件的共享状态
- 可预测的状态变更流程
- 提供全局可访问的单一数据源
二、核心概念图解
Dispatch Commit Mutate Render Vue Components Actions Mutations State
概念 | 作用 | 类比 |
---|---|---|
State | 存储应用状态数据 | 数据库 |
Mutations | 同步修改状态(唯一修改方式) | 数据库事务 |
Actions | 处理异步操作,提交Mutations | 服务员 |
Getters | 计算派生状态(类似计算属性) | 视图层过滤器 |
三、快速配置Vuex
1. 安装
bash
npm install vuex@next --save # Vue 3使用Vuex 4.x
2. 创建store
javascript
// store/index.js
import { createStore } from 'vuex'
export default createStore({
state: {
cartItems: [], // 购物车商品
totalPrice: 0 // 总金额
},
mutations: {
// 添加商品
ADD_TO_CART(state, product) {
state.cartItems.push(product)
state.totalPrice += product.price
},
// 移除商品
REMOVE_ITEM(state, index) {
const item = state.cartItems.splice(index, 1)[0]
state.totalPrice -= item.price
}
},
actions: {
// 异步结算操作
async checkout({ commit }) {
const res = await fetch('/api/checkout')
if (res.ok) {
commit('CLEAR_CART') // 调用其他mutation
}
}
},
getters: {
// 获取特价商品
discountedItems: state => {
return state.cartItems.filter(item => item.discount > 0)
}
}
})
3. 注入Vue应用
javascript
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
createApp(App).use(store).mount('#app')
四、组件中使用Vuex
1. 访问状态
vue
<template>
<div>
<h3>购物车({{ cartItemCount }})</h3>
<p>总金额:¥{{ totalPrice }}</p>
</div>
</template>
<script>
export default {
computed: {
// 通过辅助函数访问
...mapState(['totalPrice']),
...mapGetters(['cartItemCount']),
// 传统方式访问
localCount() {
return this.$store.state.cartItems.length
}
}
}
</script>
2. 修改状态
vue
<script>
import { mapMutations, mapActions } from 'vuex'
export default {
methods: {
// 映射Mutations
...mapMutations(['ADD_TO_CART']),
// 映射Actions
...mapActions(['checkout']),
// 添加商品示例
addProduct() {
const product = {
id: 1,
name: 'Vue实战教程',
price: 99,
discount: 0.2
}
this.ADD_TO_CART(product)
},
// 结算操作
handleCheckout() {
this.checkout().then(() => {
alert('结算成功!')
})
}
}
}
</script>
五、模块化开发(大型项目必备)
1. 模块结构
store/
├── index.js # 主文件
├── modules/
│ ├── cart.js # 购物车模块
│ ├── user.js # 用户模块
│ └── product.js # 商品模块
2. 购物车模块示例
javascript
// store/modules/cart.js
const cartModule = {
namespaced: true, // 启用命名空间
state: () => ({
items: []
}),
mutations: { /* ... */ },
getters: {
itemCount: state => state.items.length
}
}
export default cartModule
3. 在组件中使用命名空间
javascript
computed: {
...mapState('cart', ['items']),
...mapGetters('cart', ['itemCount'])
},
methods: {
...mapMutations('cart', ['ADD_ITEM']),
...mapActions('cart', ['fetchCart'])
}
六、最佳实践与常见问题
1. 使用原则
- 严格遵循修改流程:组件 → Actions → Mutations → State
- 避免直接修改State:必须通过commit mutations
- 模块化组织代码:当state超过100行代码时拆分
2. 调试技巧
-
使用Vue Devtools实时观察状态变化
-
开启严格模式(开发环境):
javascriptconst store = createStore({ strict: process.env.NODE_ENV !== 'production' })
3. 常见问题解决方案
-
页面刷新数据丢失
- 方案1:使用
vuex-persistedstate
插件 - 方案2:手动同步到localStorage
- 方案1:使用
-
异步操作竞态问题
javascriptactions: { async fetchData({ commit }, params) { // 取消之前的请求 if (this.cancelToken) this.cancelToken.cancel() const source = axios.CancelToken.source() this.cancelToken = source try { const res = await axios.get('/api/data', { cancelToken: source.token }) commit('SET_DATA', res.data) } catch (error) { if (!axios.isCancel(error)) { console.error(error) } } } }
七、Vuex替代方案(根据项目规模选择)
方案 | 适用场景 | 特点 |
---|---|---|
Vuex | 中大型复杂应用 | 完善生态,强类型支持 |
Pinia | Vue 3新项目 | 更简洁的API,兼容Composition API |
Event Bus | 小型简单应用 | 轻量但难以维护 |
Provide/Inject | 深层嵌套组件通信 | Vue原生方案,无全局状态管理 |
下一步学习建议
- 结合TypeScript使用Vuex
- 学习Vuex插件开发技巧
- 掌握服务端渲染(SSR)中的状态管理
如果觉得有帮助,请点赞收藏支持!更多前端技术干货,欢迎关注我的专栏~
(原创内容,转载请注明出处)