Getter进阶 #
Getter 传参详解 #
返回函数模式 #
Getter 本身不支持直接传参,但可以通过返回函数来实现:
javascript
const store = createStore({
state: {
products: [
{ id: 1, name: 'Product 1', category: 'electronics', price: 100 },
{ id: 2, name: 'Product 2', category: 'clothing', price: 50 },
{ id: 3, name: 'Product 3', category: 'electronics', price: 200 }
]
},
getters: {
// 返回函数,支持参数
productsByCategory: state => category => {
return state.products.filter(p => p.category === category)
},
// 多参数
productsByPriceRange: state => (min, max) => {
return state.products.filter(p => p.price >= min && p.price <= max)
},
// 组合参数
filterProducts: state => filters => {
let result = state.products
if (filters.category) {
result = result.filter(p => p.category === filters.category)
}
if (filters.minPrice) {
result = result.filter(p => p.price >= filters.minPrice)
}
if (filters.maxPrice) {
result = result.filter(p => p.price <= filters.maxPrice)
}
return result
}
}
})
在组件中使用 #
vue
<template>
<div>
<select v-model="selectedCategory">
<option value="">All</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
</select>
<ul>
<li v-for="product in filteredProducts" :key="product.id">
{{ product.name }} - ${{ product.price }}
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
selectedCategory: ''
}
},
computed: {
filteredProducts() {
const getter = this.$store.getters.productsByCategory
return this.selectedCategory
? getter(this.selectedCategory)
: this.$store.state.products
}
}
}
</script>
注意事项 #
javascript
// 注意:返回函数的 getter 不会缓存结果
getters: {
// 每次调用都会重新计算
getProductById: state => id => {
return state.products.find(p => p.id === id)
}
}
// 如果需要缓存,考虑使用 map 或对象
getters: {
// 这个会缓存
productsMap: state => {
const map = {}
state.products.forEach(p => {
map[p.id] = p
})
return map
}
}
// 使用时
computed: {
product() {
return this.$store.getters.productsMap[this.productId]
}
}
Getter 组合 #
链式调用 #
Getter 可以访问其他 Getter:
javascript
getters: {
// 基础 getter
cartItems: state => state.cart.items,
// 使用其他 getter
cartTotal: (state, getters) => {
return getters.cartItems.reduce((total, item) => {
return total + item.price * item.quantity
}, 0)
},
// 继续链式
cartWithTax: (state, getters) => {
return getters.cartTotal * 1.1 // 10% tax
},
// 更复杂的组合
cartSummary: (state, getters) => {
return {
items: getters.cartItems,
subtotal: getters.cartTotal,
tax: getters.cartTotal * 0.1,
total: getters.cartWithTax,
itemCount: getters.cartItems.length
}
}
}
跨模块 Getter #
javascript
// store/modules/cart.js
getters: {
cartItems: state => state.items,
cartTotal: state => state.items.reduce((t, i) => t + i.price * i.quantity, 0)
}
// store/modules/products.js
getters: {
productById: state => id => state.products.find(p => p.id === id)
}
// store/modules/user.js
getters: {
userDiscount: state => state.membershipLevel === 'vip' ? 0.9 : 1
}
// 在组件中组合
computed: {
cartWithDetails() {
const items = this.$store.getters['cart/cartItems']
const discount = this.$store.getters['user/userDiscount']
return items.map(item => {
const product = this.$store.getters['products/productById'](item.productId)
return {
...item,
product,
finalPrice: product.price * discount
}
})
}
}
在 Getter 中访问根状态 #
javascript
// 模块中的 getter
const moduleA = {
namespaced: true,
state: {
items: []
},
getters: {
// 第三和第四个参数:rootState 和 rootGetters
itemsWithUser: (state, getters, rootState, rootGetters) => {
return state.items.map(item => ({
...item,
user: rootState.user.byId[item.userId]
}))
},
// 使用 rootGetters
itemsWithDiscount: (state, getters, rootState, rootGetters) => {
const discount = rootGetters['user/discount']
return state.items.map(item => ({
...item,
discountedPrice: item.price * discount
}))
}
}
}
性能优化 #
1. 避免重复计算 #
javascript
// 不推荐:每次都计算
getters: {
expensiveList: state => {
// 复杂计算
return state.items.map(item => ({
...item,
computed: heavyCalculation(item)
}))
}
}
// 推荐:使用缓存
getters: {
// 简单 getter 会被缓存
processedItems: state => {
return state.items.map(item => ({
...item,
computed: heavyCalculation(item)
}))
}
}
2. 使用选择器模式 #
javascript
// 创建选择器
getters: {
// 基础选择器
productsById: state => {
return state.products.reduce((map, product) => {
map[product.id] = product
return map
}, {})
},
// 使用基础选择器
productById: (state, getters) => id => {
return getters.productsById[id]
}
}
// 组件中使用
computed: {
product() {
return this.$store.getters.productsById[this.productId]
}
}
3. 延迟计算 #
javascript
getters: {
// 只在需要时计算
expensiveGetter: state => {
return {
get value() {
// 延迟计算
return heavyCalculation(state.data)
}
}
}
}
实战模式 #
数据转换模式 #
javascript
state: {
rawUsers: [
{ id: 1, firstName: 'John', lastName: 'Doe', email: 'john@example.com' },
{ id: 2, firstName: 'Jane', lastName: 'Smith', email: 'jane@example.com' }
]
},
getters: {
// 转换为显示格式
usersForDisplay: state => {
return state.rawUsers.map(user => ({
id: user.id,
fullName: `${user.firstName} ${user.lastName}`,
avatar: `https://avatar.example.com/${user.email}`
}))
},
// 转换为选择器选项
userOptions: state => {
return state.rawUsers.map(user => ({
label: `${user.firstName} ${user.lastName}`,
value: user.id
}))
},
// 转换为下拉菜单数据
userSelectData: (state, getters) => ({
options: getters.userOptions,
selected: null
})
}
分页模式 #
javascript
state: {
posts: [], // 所有文章
pageSize: 10,
currentPage: 1
},
getters: {
totalPages: state => Math.ceil(state.posts.length / state.pageSize),
paginatedPosts: state => {
const start = (state.currentPage - 1) * state.pageSize
const end = start + state.pageSize
return state.posts.slice(start, end)
},
pagination: (state, getters) => ({
currentPage: state.currentPage,
totalPages: getters.totalPages,
hasNext: state.currentPage < getters.totalPages,
hasPrev: state.currentPage > 1,
items: getters.paginatedPosts
})
}
搜索过滤模式 #
javascript
state: {
products: [],
searchQuery: '',
filters: {
category: null,
minPrice: null,
maxPrice: null,
inStock: null
}
},
getters: {
filteredProducts: state => {
let result = state.products
// 搜索
if (state.searchQuery) {
const query = state.searchQuery.toLowerCase()
result = result.filter(p =>
p.name.toLowerCase().includes(query) ||
p.description.toLowerCase().includes(query)
)
}
// 分类过滤
if (state.filters.category) {
result = result.filter(p => p.category === state.filters.category)
}
// 价格过滤
if (state.filters.minPrice !== null) {
result = result.filter(p => p.price >= state.filters.minPrice)
}
if (state.filters.maxPrice !== null) {
result = result.filter(p => p.price <= state.filters.maxPrice)
}
// 库存过滤
if (state.filters.inStock !== null) {
result = result.filter(p => p.inStock === state.filters.inStock)
}
return result
},
// 分组
productsByCategory: (state, getters) => {
const groups = {}
getters.filteredProducts.forEach(product => {
if (!groups[product.category]) {
groups[product.category] = []
}
groups[product.category].push(product)
})
return groups
}
}
TypeScript 支持 #
typescript
// types.ts
interface User {
id: number
name: string
email: string
}
interface RootState {
users: User[]
currentUserId: number | null
}
// store.ts
import { GetterTree } from 'vuex'
const getters: GetterTree<RootState, RootState> = {
currentUser: (state): User | null => {
return state.users.find(u => u.id === state.currentUserId) || null
},
userById: (state) => (id: number): User | undefined => {
return state.users.find(u => u.id === id)
}
}
总结 #
Getter 进阶要点:
| 技巧 | 说明 |
|---|---|
| 传参 | 返回函数实现参数传递 |
| 组合 | Getter 可以访问其他 Getter |
| 跨模块 | 使用 rootState 和 rootGetters |
| 性能 | 利用缓存、避免重复计算 |
继续学习 Mutation基础,了解如何修改状态。
最后更新:2026-03-28