Search K
Appearance
Appearance
📊 SEO元描述:2024年最新Vuex核心教程,详解State状态、Getters计算属性、Mutations同步变更、Actions异步操作、Modules模块化。包含完整代码示例和最佳实践,适合前端开发者深入掌握Vuex核心功能。
核心关键词:Vuex核心2024、Vuex State、Vuex Getters、Vuex Mutations、Vuex Actions、Vuex Modules、Vue2教程
长尾关键词:Vuex State怎么用、Vuex Getters计算属性、Vuex Mutations同步操作、Vuex Actions异步操作、Vuex模块化管理
通过本节Vuex核心教程,你将系统性掌握:
Vuex核心是什么?这是Vuex状态管理的五大核心概念:State、Getters、Mutations、Actions、Modules。深入理解这些核心功能是构建高质量应用的关键技术。
💡 学习建议:Vuex核心功能环环相扣,建议按照State→Getters→Mutations→Actions→Modules的顺序学习,重点理解每个部分的职责和使用场景。
State是Vuex的核心,存储应用的所有状态数据:
// 🎉 State状态管理示例
const store = new Vuex.Store({
state: {
// 用户认证状态
auth: {
user: null,
token: localStorage.getItem('token'),
isLoggedIn: false,
loginAttempts: 0,
lastLoginTime: null
},
// 应用数据状态
data: {
products: [],
categories: [],
cart: {
items: [],
coupon: null,
shippingAddress: null
},
orders: [],
wishlist: []
},
// UI状态
ui: {
loading: {
global: false,
products: false,
cart: false,
checkout: false
},
errors: {
login: null,
products: null,
cart: null
},
modals: {
login: false,
productDetail: null,
cart: false
},
notifications: [],
theme: localStorage.getItem('theme') || 'light',
language: localStorage.getItem('language') || 'zh-CN'
},
// 应用配置
config: {
apiBaseUrl: process.env.VUE_APP_API_URL,
version: '1.0.0',
features: {
enableWishlist: true,
enableReviews: true,
enableCoupons: false
},
pagination: {
defaultPageSize: 20,
maxPageSize: 100
}
}
}
})
// 在组件中访问State
const UserProfile = {
template: `
<div class="user-profile">
<div v-if="isLoggedIn" class="user-info">
<h2>欢迎,{{ user.name }}</h2>
<p>邮箱: {{ user.email }}</p>
<p>上次登录: {{ formatDate(lastLoginTime) }}</p>
</div>
<div v-else class="login-prompt">
<p>请先登录</p>
<button @click="showLoginModal">登录</button>
</div>
<div class="user-stats">
<div class="stat">
<span class="label">购物车商品</span>
<span class="value">{{ cartItemCount }}</span>
</div>
<div class="stat">
<span class="label">心愿单商品</span>
<span class="value">{{ wishlistCount }}</span>
</div>
<div class="stat">
<span class="label">历史订单</span>
<span class="value">{{ orderCount }}</span>
</div>
</div>
</div>
`,
computed: {
// 直接访问state
user() {
return this.$store.state.auth.user
},
isLoggedIn() {
return this.$store.state.auth.isLoggedIn
},
lastLoginTime() {
return this.$store.state.auth.lastLoginTime
},
cartItemCount() {
return this.$store.state.data.cart.items.length
},
wishlistCount() {
return this.$store.state.data.wishlist.length
},
orderCount() {
return this.$store.state.data.orders.length
}
},
methods: {
showLoginModal() {
this.$store.commit('SET_MODAL_STATE', { modal: 'login', state: true })
},
formatDate(date) {
return date ? new Date(date).toLocaleString() : '从未登录'
}
}
}Getters从state中派生出一些状态,类似于Vue的计算属性:
// 🎉 Getters计算属性示例
const store = new Vuex.Store({
state: {
products: [
{ id: 1, name: '商品1', price: 100, category: 'electronics', inStock: true, rating: 4.5 },
{ id: 2, name: '商品2', price: 200, category: 'clothing', inStock: false, rating: 3.8 },
{ id: 3, name: '商品3', price: 150, category: 'electronics', inStock: true, rating: 4.2 }
],
cart: {
items: [
{ productId: 1, quantity: 2, price: 100 },
{ productId: 3, quantity: 1, price: 150 }
]
},
filters: {
category: '',
priceRange: { min: 0, max: 1000 },
inStockOnly: false,
minRating: 0
}
},
getters: {
// 基础getters
productCount: state => state.products.length,
// 有库存的商品
inStockProducts: state => {
return state.products.filter(product => product.inStock)
},
// 根据分类筛选商品
productsByCategory: state => category => {
return state.products.filter(product => product.category === category)
},
// 复杂的商品筛选
filteredProducts: state => {
return state.products.filter(product => {
// 分类筛选
if (state.filters.category && product.category !== state.filters.category) {
return false
}
// 价格范围筛选
if (product.price < state.filters.priceRange.min ||
product.price > state.filters.priceRange.max) {
return false
}
// 库存筛选
if (state.filters.inStockOnly && !product.inStock) {
return false
}
// 评分筛选
if (product.rating < state.filters.minRating) {
return false
}
return true
})
},
// 购物车相关getters
cartItems: (state, getters) => {
return state.cart.items.map(cartItem => {
const product = getters.getProductById(cartItem.productId)
return {
...cartItem,
product,
total: cartItem.quantity * cartItem.price
}
})
},
cartTotal: (state, getters) => {
return getters.cartItems.reduce((total, item) => total + item.total, 0)
},
cartItemCount: state => {
return state.cart.items.reduce((count, item) => count + item.quantity, 0)
},
// 根据ID获取商品(带参数的getter)
getProductById: state => id => {
return state.products.find(product => product.id === id)
},
// 商品统计信息
productStats: state => {
const stats = {
total: state.products.length,
inStock: 0,
outOfStock: 0,
categories: {},
averagePrice: 0,
averageRating: 0
}
let totalPrice = 0
let totalRating = 0
state.products.forEach(product => {
// 库存统计
if (product.inStock) {
stats.inStock++
} else {
stats.outOfStock++
}
// 分类统计
if (!stats.categories[product.category]) {
stats.categories[product.category] = 0
}
stats.categories[product.category]++
// 价格和评分累计
totalPrice += product.price
totalRating += product.rating
})
// 计算平均值
stats.averagePrice = totalPrice / stats.total
stats.averageRating = totalRating / stats.total
return stats
},
// 推荐商品(基于其他getters)
recommendedProducts: (state, getters) => {
return getters.inStockProducts
.filter(product => product.rating >= 4.0)
.sort((a, b) => b.rating - a.rating)
.slice(0, 5)
}
}
})
// 在组件中使用Getters
const ProductList = {
template: `
<div class="product-list">
<div class="filters">
<select v-model="selectedCategory" @change="updateCategoryFilter">
<option value="">全部分类</option>
<option v-for="(count, category) in productStats.categories"
:key="category" :value="category">
{{ category }} ({{ count }})
</option>
</select>
<label>
<input type="checkbox" v-model="inStockOnly" @change="updateStockFilter">
仅显示有库存商品
</label>
<div class="price-range">
<label>价格范围:</label>
<input type="range" v-model="priceRange.min" min="0" max="500">
<input type="range" v-model="priceRange.max" min="0" max="1000">
<span>¥{{ priceRange.min }} - ¥{{ priceRange.max }}</span>
</div>
</div>
<div class="product-stats">
<p>共 {{ filteredProducts.length }} 个商品</p>
<p>平均价格: ¥{{ productStats.averagePrice.toFixed(2) }}</p>
<p>平均评分: {{ productStats.averageRating.toFixed(1) }}</p>
</div>
<div class="products">
<div v-for="product in filteredProducts" :key="product.id" class="product-card">
<h3>{{ product.name }}</h3>
<p class="price">¥{{ product.price }}</p>
<p class="rating">评分: {{ product.rating }}</p>
<p class="stock" :class="{ 'out-of-stock': !product.inStock }">
{{ product.inStock ? '有库存' : '缺货' }}
</p>
<button @click="addToCart(product)" :disabled="!product.inStock">
加入购物车
</button>
</div>
</div>
<div class="recommendations">
<h3>推荐商品</h3>
<div v-for="product in recommendedProducts" :key="product.id" class="recommended-item">
{{ product.name }} - ¥{{ product.price }}
</div>
</div>
</div>
`,
data() {
return {
selectedCategory: '',
inStockOnly: false,
priceRange: { min: 0, max: 1000 }
}
},
computed: {
// 使用getters
filteredProducts() {
return this.$store.getters.filteredProducts
},
productStats() {
return this.$store.getters.productStats
},
recommendedProducts() {
return this.$store.getters.recommendedProducts
}
},
methods: {
updateCategoryFilter() {
this.$store.commit('SET_CATEGORY_FILTER', this.selectedCategory)
},
updateStockFilter() {
this.$store.commit('SET_STOCK_FILTER', this.inStockOnly)
},
addToCart(product) {
this.$store.dispatch('addToCart', product)
}
},
watch: {
priceRange: {
handler(newRange) {
this.$store.commit('SET_PRICE_RANGE_FILTER', newRange)
},
deep: true
}
}
}Mutations是更改Vuex store中状态的唯一方法,必须是同步函数:
// 🎉 Mutations同步变更示例
const store = new Vuex.Store({
state: {
user: null,
products: [],
cart: { items: [] },
ui: { loading: false, errors: {} }
},
mutations: {
// 用户相关mutations
SET_USER(state, user) {
state.user = user
},
UPDATE_USER(state, userData) {
if (state.user) {
state.user = { ...state.user, ...userData }
}
},
CLEAR_USER(state) {
state.user = null
},
// 产品相关mutations
SET_PRODUCTS(state, products) {
state.products = products
},
ADD_PRODUCT(state, product) {
state.products.push(product)
},
UPDATE_PRODUCT(state, { id, updates }) {
const index = state.products.findIndex(p => p.id === id)
if (index !== -1) {
state.products.splice(index, 1, { ...state.products[index], ...updates })
}
},
REMOVE_PRODUCT(state, productId) {
state.products = state.products.filter(p => p.id !== productId)
},
// 购物车相关mutations
ADD_TO_CART(state, { product, quantity = 1 }) {
const existingItem = state.cart.items.find(item => item.productId === product.id)
if (existingItem) {
existingItem.quantity += quantity
} else {
state.cart.items.push({
productId: product.id,
quantity,
price: product.price,
addedAt: new Date().toISOString()
})
}
},
REMOVE_FROM_CART(state, productId) {
state.cart.items = state.cart.items.filter(item => item.productId !== productId)
},
UPDATE_CART_QUANTITY(state, { productId, quantity }) {
const item = state.cart.items.find(item => item.productId === productId)
if (item) {
if (quantity <= 0) {
// 数量为0时移除商品
state.cart.items = state.cart.items.filter(item => item.productId !== productId)
} else {
item.quantity = quantity
}
}
},
CLEAR_CART(state) {
state.cart.items = []
},
// UI状态mutations
SET_LOADING(state, { type, status }) {
state.ui.loading = status
},
SET_ERROR(state, { type, error }) {
state.ui.errors = { ...state.ui.errors, [type]: error }
},
CLEAR_ERROR(state, type) {
const errors = { ...state.ui.errors }
delete errors[type]
state.ui.errors = errors
},
CLEAR_ALL_ERRORS(state) {
state.ui.errors = {}
},
// 复杂的mutations示例
BATCH_UPDATE_PRODUCTS(state, updates) {
updates.forEach(({ id, data }) => {
const index = state.products.findIndex(p => p.id === id)
if (index !== -1) {
state.products.splice(index, 1, { ...state.products[index], ...data })
}
})
},
SORT_PRODUCTS(state, { field, order = 'asc' }) {
state.products.sort((a, b) => {
const aValue = a[field]
const bValue = b[field]
if (order === 'asc') {
return aValue > bValue ? 1 : -1
} else {
return aValue < bValue ? 1 : -1
}
})
},
// 使用payload对象的mutations
UPDATE_FILTERS(state, filters) {
state.filters = { ...state.filters, ...filters }
}
}
})
// Mutations的使用规范
const MutationExample = {
methods: {
// 正确的mutations调用方式
updateUser() {
// 提交mutation
this.$store.commit('SET_USER', {
id: 1,
name: '张三',
email: 'zhangsan@example.com'
})
},
// 使用对象风格提交
updateUserObjectStyle() {
this.$store.commit({
type: 'UPDATE_USER',
name: '李四',
email: 'lisi@example.com'
})
},
// 批量操作
batchUpdateProducts() {
const updates = [
{ id: 1, data: { price: 120 } },
{ id: 2, data: { inStock: false } }
]
this.$store.commit('BATCH_UPDATE_PRODUCTS', updates)
},
// 错误处理
handleError(error) {
this.$store.commit('SET_ERROR', {
type: 'products',
error: error.message
})
},
clearError() {
this.$store.commit('CLEAR_ERROR', 'products')
}
}
}Actions提交mutations,可以包含任意异步操作:
// 🎉 Actions异步操作示例
const store = new Vuex.Store({
state: {
user: null,
products: [],
cart: { items: [] },
orders: []
},
actions: {
// 用户登录
async login({ commit, dispatch }, credentials) {
commit('SET_LOADING', { type: 'auth', status: true })
commit('CLEAR_ERROR', 'auth')
try {
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(credentials)
})
if (!response.ok) {
throw new Error('登录失败')
}
const { user, token } = await response.json()
// 保存token
localStorage.setItem('token', token)
// 更新用户状态
commit('SET_USER', user)
// 登录成功后加载用户数据
await dispatch('loadUserData')
return { success: true, user }
} catch (error) {
commit('SET_ERROR', { type: 'auth', error: error.message })
return { success: false, error: error.message }
} finally {
commit('SET_LOADING', { type: 'auth', status: false })
}
},
// 加载用户数据
async loadUserData({ commit, state }) {
if (!state.user) return
try {
// 并行加载用户的购物车和订单
const [cartResponse, ordersResponse] = await Promise.all([
fetch(`/api/users/${state.user.id}/cart`),
fetch(`/api/users/${state.user.id}/orders`)
])
const [cartData, ordersData] = await Promise.all([
cartResponse.json(),
ordersResponse.json()
])
commit('SET_CART', cartData)
commit('SET_ORDERS', ordersData)
} catch (error) {
console.error('加载用户数据失败:', error)
}
},
// 加载产品列表
async loadProducts({ commit, state }, { page = 1, pageSize = 20, filters = {} } = {}) {
commit('SET_LOADING', { type: 'products', status: true })
try {
const queryParams = new URLSearchParams({
page,
pageSize,
...filters
})
const response = await fetch(`/api/products?${queryParams}`)
const data = await response.json()
if (page === 1) {
commit('SET_PRODUCTS', data.products)
} else {
commit('APPEND_PRODUCTS', data.products)
}
return { success: true, data }
} catch (error) {
commit('SET_ERROR', { type: 'products', error: error.message })
return { success: false, error: error.message }
} finally {
commit('SET_LOADING', { type: 'products', status: false })
}
},
// 添加到购物车(带API同步)
async addToCart({ commit, state, dispatch }, product) {
// 先更新本地状态
commit('ADD_TO_CART', { product })
// 如果用户已登录,同步到服务器
if (state.user) {
try {
await fetch(`/api/users/${state.user.id}/cart`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
productId: product.id,
quantity: 1
})
})
} catch (error) {
// 同步失败,回滚本地状态
commit('REMOVE_FROM_CART', product.id)
commit('SET_ERROR', { type: 'cart', error: '添加到购物车失败' })
throw error
}
}
},
// 创建订单
async createOrder({ commit, state, dispatch }, orderData) {
commit('SET_LOADING', { type: 'checkout', status: true })
try {
const response = await fetch('/api/orders', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('token')}`
},
body: JSON.stringify({
...orderData,
items: state.cart.items,
userId: state.user.id
})
})
if (!response.ok) {
throw new Error('订单创建失败')
}
const order = await response.json()
// 添加订单到状态
commit('ADD_ORDER', order)
// 清空购物车
commit('CLEAR_CART')
// 同步清空服务器购物车
if (state.user) {
await dispatch('clearServerCart')
}
return { success: true, order }
} catch (error) {
commit('SET_ERROR', { type: 'checkout', error: error.message })
return { success: false, error: error.message }
} finally {
commit('SET_LOADING', { type: 'checkout', status: false })
}
},
// 复杂的组合action
async refreshUserData({ dispatch, commit }) {
commit('SET_LOADING', { type: 'global', status: true })
try {
// 串行执行相关操作
await dispatch('loadUserData')
await dispatch('loadProducts')
// 并行执行独立操作
await Promise.all([
dispatch('loadRecommendations'),
dispatch('loadNotifications')
])
return { success: true }
} catch (error) {
commit('SET_ERROR', { type: 'global', error: '数据刷新失败' })
return { success: false, error: error.message }
} finally {
commit('SET_LOADING', { type: 'global', status: false })
}
}
}
})
// 在组件中使用Actions
const ShoppingComponent = {
methods: {
async handleLogin() {
const credentials = {
email: this.email,
password: this.password
}
const result = await this.$store.dispatch('login', credentials)
if (result.success) {
this.$router.push('/dashboard')
} else {
alert('登录失败: ' + result.error)
}
},
async loadMoreProducts() {
const result = await this.$store.dispatch('loadProducts', {
page: this.currentPage + 1,
filters: this.filters
})
if (result.success) {
this.currentPage++
}
},
async addProductToCart(product) {
try {
await this.$store.dispatch('addToCart', product)
this.$message.success('商品已添加到购物车')
} catch (error) {
this.$message.error('添加失败,请重试')
}
}
}
}通过本节Vuex核心教程的学习,你已经掌握:
A: State存储数据,Getters计算派生状态,Mutations同步修改状态,Actions处理异步操作并提交Mutations。这是Vuex的核心数据流:Actions → Mutations → State → Getters。
A: 同步的Mutations确保状态变化是可追踪的,便于调试和时间旅行。异步操作会导致状态变化的时机不确定,破坏调试工具的功能。
A: 当需要对State进行计算、过滤、格式化时使用Getters。Getters有缓存机制,只有依赖的State变化时才重新计算,提升性能。
A: 使用try-catch捕获错误,通过Mutations更新错误状态,返回包含成功/失败信息的对象。可以在Actions中进行错误重试和降级处理。
A: 使用dispatch方法调用其他Actions,可以使用await等待异步Actions完成。注意避免循环调用和合理设计Actions的依赖关系。
// 问题:在Mutations中进行异步操作
// 解决:将异步操作移到Actions中
// ❌ 错误示例
mutations: {
async LOAD_DATA(state) {
const data = await fetch('/api/data') // 异步操作
state.data = data
}
}
// ✅ 正确示例
actions: {
async loadData({ commit }) {
const data = await fetch('/api/data')
commit('SET_DATA', data)
}
},
mutations: {
SET_DATA(state, data) {
state.data = data
}
}// 问题:Getters依赖循环或性能问题
// 解决:优化Getters设计和依赖关系
// ❌ 问题示例
getters: {
expensiveGetter: state => {
// 每次都进行复杂计算
return state.items.map(item => {
return heavyComputation(item) // 重计算
})
}
}
// ✅ 优化示例
getters: {
expensiveGetter: (state, getters) => {
// 利用其他getters的缓存
return getters.processedItems.filter(item => item.isValid)
},
processedItems: state => {
// 基础计算,会被缓存
return state.items.map(item => processItem(item))
}
}// 问题:Actions中错误处理不完善
// 解决:完善错误处理和状态管理
// ❌ 错误示例
actions: {
async loadData({ commit }) {
const data = await fetch('/api/data') // 没有错误处理
commit('SET_DATA', data)
}
}
// ✅ 正确示例
actions: {
async loadData({ commit }) {
commit('SET_LOADING', true)
commit('CLEAR_ERROR')
try {
const response = await fetch('/api/data')
if (!response.ok) {
throw new Error(`HTTP ${response.status}`)
}
const data = await response.json()
commit('SET_DATA', data)
return { success: true, data }
} catch (error) {
commit('SET_ERROR', error.message)
return { success: false, error: error.message }
} finally {
commit('SET_LOADING', false)
}
}
}"掌握Vuex核心功能是构建复杂Vue应用的关键,理解State、Getters、Mutations、Actions的职责和协作关系,能让你的状态管理更加清晰和高效!"