Vuex状态管理 #
一、Vuex简介 #
Vuex是Vue.js的状态管理模式,采用集中式存储管理应用的所有组件的状态。
1.1 安装 #
bash
npm install vuex@next
1.2 基本配置 #
javascript
// store/index.js
import { createStore } from 'vuex'
export default createStore({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
},
actions: {
increment({ commit }) {
commit('increment')
}
},
getters: {
doubledCount(state) {
return state.count * 2
}
}
})
javascript
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
const app = createApp(App)
app.use(store)
app.mount('#app')
二、核心概念 #
2.1 State #
javascript
// store/index.js
export default createStore({
state: {
count: 0,
user: {
name: '张三',
age: 25
},
todos: [
{ id: 1, text: '学习Vue', completed: false },
{ id: 2, text: '学习Vuex', completed: true }
]
}
})
vue
<template>
<div>
<p>计数: {{ $store.state.count }}</p>
<p>用户: {{ $store.state.user.name }}</p>
</div>
</template>
<script setup>
import { useStore } from 'vuex'
import { computed } from 'vue'
const store = useStore()
// 访问state
console.log(store.state.count)
// 使用computed保持响应性
const count = computed(() => store.state.count)
</script>
2.2 mapState辅助函数 #
vue
<script setup>
import { useStore, mapState } from 'vuex'
import { computed } from 'vue'
const store = useStore()
// 使用mapState
const { count, user } = mapState(['count', 'user'])
// 或展开使用
const count = computed(() => store.state.count)
const userName = computed(() => store.state.user.name)
</script>
三、Getters #
3.1 定义Getters #
javascript
export default createStore({
state: {
todos: [
{ id: 1, text: '学习Vue', completed: false },
{ id: 2, text: '学习Vuex', completed: true }
]
},
getters: {
// 基本getter
doneTodos: (state) => {
return state.todos.filter(todo => todo.completed)
},
// 返回函数
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
},
// 访问其他getter
doneTodosCount: (state, getters) => {
return getters.doneTodos.length
}
}
})
3.2 使用Getters #
vue
<template>
<div>
<p>已完成: {{ $store.getters.doneTodosCount }}</p>
</div>
</template>
<script setup>
import { useStore } from 'vuex'
import { computed } from 'vue'
const store = useStore()
// 访问getter
const doneTodos = computed(() => store.getters.doneTodos)
const doneTodosCount = computed(() => store.getters.doneTodosCount)
// 使用返回函数的getter
const todo = store.getters.getTodoById(1)
</script>
四、Mutations #
4.1 定义Mutations #
javascript
export default createStore({
state: {
count: 0,
user: null
},
mutations: {
increment(state) {
state.count++
},
incrementBy(state, payload) {
state.count += payload.amount
},
setUser(state, user) {
state.user = user
},
// 对象风格的提交
updateUser(state, { field, value }) {
state.user[field] = value
}
}
})
4.2 提交Mutations #
vue
<script setup>
import { useStore } from 'vuex'
const store = useStore()
// 基本提交
store.commit('increment')
// 载荷提交
store.commit('incrementBy', { amount: 10 })
// 对象风格提交
store.commit({
type: 'incrementBy',
amount: 10
})
</script>
4.3 Mutation规则 #
javascript
// ✅ 正确:同步操作
mutations: {
increment(state) {
state.count++
}
}
// ❌ 错误:异步操作
mutations: {
increment(state) {
setTimeout(() => {
state.count++ // 不要这样做!
}, 1000)
}
}
五、Actions #
5.1 定义Actions #
javascript
export default createStore({
state: {
products: [],
loading: false
},
mutations: {
setProducts(state, products) {
state.products = products
},
setLoading(state, loading) {
state.loading = loading
}
},
actions: {
async fetchProducts({ commit }) {
commit('setLoading', true)
try {
const response = await fetch('/api/products')
const products = await response.json()
commit('setProducts', products)
} finally {
commit('setLoading', false)
}
},
async addProduct({ commit }, product) {
const response = await fetch('/api/products', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(product)
})
const newProduct = await response.json()
commit('addProduct', newProduct)
},
// 组合action
async fetchAndProcess({ dispatch, commit }) {
await dispatch('fetchProducts')
// 处理数据
commit('processProducts')
}
}
})
5.2 分发Actions #
vue
<script setup>
import { useStore } from 'vue'
import { onMounted } from 'vue'
const store = useStore()
// 分发action
store.dispatch('fetchProducts')
// 带载荷
store.dispatch('addProduct', { name: '新产品', price: 99 })
// 对象风格
store.dispatch({
type: 'addProduct',
product: { name: '新产品', price: 99 }
})
// 处理Promise
onMounted(async () => {
await store.dispatch('fetchProducts')
console.log('数据加载完成')
})
</script>
六、Modules #
6.1 定义模块 #
javascript
// store/modules/user.js
export default {
namespaced: true,
state: {
user: null,
token: null
},
mutations: {
setUser(state, user) {
state.user = user
},
setToken(state, token) {
state.token = token
}
},
actions: {
async login({ commit }, credentials) {
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(credentials)
})
const data = await response.json()
commit('setUser', data.user)
commit('setToken', data.token)
},
logout({ commit }) {
commit('setUser', null)
commit('setToken', null)
}
},
getters: {
isLoggedIn: state => !!state.token,
userName: state => state.user?.name
}
}
6.2 注册模块 #
javascript
// store/index.js
import { createStore } from 'vuex'
import user from './modules/user'
import product from './modules/product'
export default createStore({
modules: {
user,
product
}
})
6.3 使用模块 #
vue
<script setup>
import { useStore } from 'vuex'
import { computed } from 'vue'
const store = useStore()
// 访问模块state
const user = computed(() => store.state.user.user)
const token = computed(() => store.state.user.token)
// 访问模块getter
const isLoggedIn = computed(() => store.getters['user/isLoggedIn'])
// 提交模块mutation
store.commit('user/setUser', { name: '张三' })
// 分发模块action
store.dispatch('user/login', { username: 'admin', password: '123456' })
</script>
七、完整示例 #
javascript
// store/index.js
import { createStore } from 'vuex'
export default createStore({
state: {
cart: [],
products: []
},
mutations: {
ADD_TO_CART(state, product) {
const item = state.cart.find(i => i.id === product.id)
if (item) {
item.quantity++
} else {
state.cart.push({ ...product, quantity: 1 })
}
},
REMOVE_FROM_CART(state, productId) {
state.cart = state.cart.filter(i => i.id !== productId)
},
UPDATE_QUANTITY(state, { productId, quantity }) {
const item = state.cart.find(i => i.id === productId)
if (item) {
item.quantity = quantity
}
},
SET_PRODUCTS(state, products) {
state.products = products
}
},
actions: {
async fetchProducts({ commit }) {
const response = await fetch('/api/products')
const products = await response.json()
commit('SET_PRODUCTS', products)
},
addToCart({ commit, state }, product) {
commit('ADD_TO_CART', product)
// 可以在这里保存到本地存储
localStorage.setItem('cart', JSON.stringify(state.cart))
}
},
getters: {
cartTotal: state => {
return state.cart.reduce((total, item) => {
return total + item.price * item.quantity
}, 0)
},
cartItemCount: state => {
return state.cart.reduce((count, item) => count + item.quantity, 0)
},
productById: state => id => {
return state.products.find(p => p.id === id)
}
}
})
vue
<template>
<div>
<h2>购物车</h2>
<p>商品数量: {{ cartItemCount }}</p>
<p>总价: ¥{{ cartTotal }}</p>
<div v-for="item in cart" :key="item.id">
{{ item.name }} - ¥{{ item.price }} x {{ item.quantity }}
<button @click="removeFromCart(item.id)">删除</button>
</div>
</div>
</template>
<script setup>
import { useStore } from 'vuex'
import { computed } from 'vue'
const store = useStore()
const cart = computed(() => store.state.cart)
const cartTotal = computed(() => store.getters.cartTotal)
const cartItemCount = computed(() => store.getters.cartItemCount)
function removeFromCart(productId) {
store.commit('REMOVE_FROM_CART', productId)
}
</script>
八、总结 #
Vuex核心概念 #
| 概念 | 说明 |
|---|---|
| State | 状态数据 |
| Getters | 计算属性 |
| Mutations | 同步修改状态 |
| Actions | 异步操作 |
Vuex要点:
- State存储应用状态
- Getters派生状态
- Mutations同步修改状态
- Actions处理异步操作
- Modules模块化管理
- 使用命名空间避免冲突
最后更新:2026-03-26