Vue.js - 使用Vuex进行状态管理详解3(getters全局计算属性)
作者:hangge | 2026-10-01 09:59
在前文中,我们介绍了 Vuex 中 state 的基本使用方式,包括直接访问和通过 mapState 辅助函数映射。但在实际开发中,我们经常需要对 state 中的数据进行加工处理后再使用,比如过滤列表、计算总价、格式化数据等。 如果在每个组件中都写一遍相同的计算逻辑,不仅代码冗余,维护起来也非常麻烦。为了解决这个问题,Vuex 提供了 getters,可以理解为 store 的计算属性。本文将详细介绍 getters 的各种用法,包括基本使用、参数传递、返回函数以及 mapGetters 辅助函数的使用技巧。

一、基本介绍
1,getters 是什么?
(1)getters 可以理解为 Vuex store 的计算属性。它允许我们从 store 的 state 中派生出一些状态,例如对列表进行过滤、计算总和等操作。
(2)与组件中的计算属性类似,getters 会根据它的依赖自动缓存结果,只有当依赖的 state 发生变化时才会重新计算。
提示:从 Vue 3.0 开始,getter 的结果不再像计算属性一样会被缓存起来(这是一个已知问题)。如果你需要缓存功能,建议在组件中再次使用计算属性包装。
2,为什么需要 getters?
(1)假设我们有多个组件都需要用到同一个计算逻辑,比如计算购物车总价、过滤已完成的待办事项等。如果不使用 getters,通常有两种方案:
- 方案一:在每个组件的 computed 中复制相同的计算代码
- 方案二:封装成一个公共函数,在多个组件中导入使用
(2)但这两种方式都不够理想:方案一会导致代码冗余,方案二虽然复用了代码但仍然需要在每个组件中导入。
(3)使用 getters 后,我们可以在 store 中统一定义计算逻辑,然后让所有组件共享使用,既避免了代码冗余,又无需手动导入。
二、getters 基本使用
1,定义 getters
下面通过一个案例来演示 getters 的基本使用。该案例的功能是:计算购物车中书籍的总价。首先在 src/store/index.js 文件中定义 state 和 getters:
- 可以看到,在 getters 中,我们定义了一个名为 totalPrice 的方法,该方法的第一个参数会自动获取 state 对象。接着,遍历 state.books,计算购买书籍的总价并返回。
import { createStore } from 'vuex'
const store = createStore({
state() {
return {
// 购物车书籍列表
books: [
{ name: 'Vue.js', count: 10, price: 10 },
{ name: 'React', count: 5, price: 20 },
{ name: 'Webpack', count: 4, price: 25 }
],
// 书籍折扣(暂未使用,后续案例会用到)
discount: 0.9
}
},
// 定义 getters
getters: {
// 计算购买的书籍总价
totalPrice(state) {
let totalPrice = 0
for (const book of state.books) {
totalPrice += book.count * book.price
}
return totalPrice
}
}
})
export default store
2,在组件中使用 getters
(1)定义好 getters 后,我们可以在组件中通过 $store.getters 访问。新建一个组件文件:
<template>
<div>
<h4>书籍总价:{{ $store.getters.totalPrice }}</h4>
</div>
</template>
<script>
export default {}
</script>
(2)保存代码后,在浏览器中运行效果如下,可以看到书籍总价为 300 元:

三、getters 方法的参数
1,参数说明
getters 中定义的方法可以接收多个参数:
- 第一个参数:state 对象,可以访问 store 中定义的状态
- 第二个参数:getters 对象,可以访问其他 getter
提示:如果在模块中定义 getter,还会有第三个参数 rootState(全局 state)和第四个参数 rootGetters(所有 getters)。
2,使用 getters 参数
(1)继续完善上面的案例,我们让书籍总价应用折扣。修改 store/index.js 文件,为 totalPrice 方法增加了第二个参数,用于接收 getters 对象,然后通过该对象访问 currentDiscount 方法获取折扣值。
import { createStore } from 'vuex'
const store = createStore({
state() {
return {
books: [
{ name: 'Vue.js', count: 10, price: 10 },
{ name: 'React', count: 5, price: 20 },
{ name: 'Webpack', count: 4, price: 25 }
],
discount: 0.9 // 书籍打9折
}
},
getters: {
// 获取当前的折扣
currentDiscount(state) {
return state.discount
},
// 计算书籍总价(应用折扣)
totalPrice(state, getters) {
let totalPrice = 0
for (const book of state.books) {
totalPrice += book.count * book.price
}
// 通过 getters 访问当前折扣
return totalPrice * getters.currentDiscount
}
}
})
export default store
(2)保存代码后,在浏览器中运行,可以看到购买书籍总价打 9 折后为 270 元:

四、getters 返回函数类型
1,返回函数的作用
(1)getters 中定义的方法不仅可以返回值,还支持返回一个函数。如果返回的是函数,那么在使用时相当于调用这个函数。
(2)这种方式可以让我们向 getter 传递参数,以实现数据的动态查询或过滤。比如:计算某本书的总价、根据 ID 查找某条数据等。
注意:getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果。如果需要缓存,建议在组件中再包装一层计算属性。
2,使用示例
(1)继续修改 store/index.js,在 getters 中添加 totalPriceByName 方法。totalPriceByName 方法返回的是一个函数,该函数接收 bookName 参数,用于筛选指定的书籍并计算总价。
import { createStore } from 'vuex'
const store = createStore({
state() {
return {
books: [
{ name: 'Vue.js', count: 10, price: 10 },
{ name: 'React', count: 5, price: 20 },
{ name: 'Webpack', count: 4, price: 25 },
],
discount: 0.9, // 书籍打9折
}
},
getters: {
// 获取当前的折扣
currentDiscount(state) {
return state.discount
},
// 计算书籍总价(应用折扣)
totalPrice(state, getters) {
let totalPrice = 0
for (const book of state.books) {
totalPrice += book.count * book.price
}
// 通过 getters 访问当前折扣
return totalPrice * getters.currentDiscount
},
// 计算指定书籍的总价
totalPriceByName(state) {
// 返回一个函数,该函数接收 bookName 参数
return (bookName) => {
let totalPrice = 0
for (const book of state.books) {
if (bookName === book.name) {
// 只计算当前这本书的总价
totalPrice += book.count * book.price
}
}
return totalPrice
}
},
},
})
export default store
(2)在组件中使用时,我们需要调用这个返回的函数并传入参数:
<template>
<div>
<h4>书籍总价:{{ $store.getters.totalPrice }}</h4>
<h4>Vue.js 书籍总价:{{ $store.getters.totalPriceByName('Vue.js') }}</h4>
</div>
</template>
<script>
export default {}
</script>
(3)保存代码后,在浏览器中运行效果如下:

五、mapGetters 辅助函数
1,在 computed 属性中使用
(1)与 mapState 类似,Vuex 提供了 mapGetters 辅助函数,用于简化获取 getters 的操作,将 store 中的 getter 映射到局部计算属性。
(2)mapGetters 支持两种语法形式:
提示:使用对象形式时,键名是组件中使用的属性名,值是 store 中 getter 的名称。这样可以将 getter 重命名为更简洁或更符合当前组件语境的名称。
<template>
<div>
<h4>书籍总价:{{ totalPrice }}</h4>
<h4>书籍折扣:{{ discount }}</h4>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
// 方式一:接收数组(使用相同的名称)
...mapGetters(['totalPrice']),
// 方式二:接收对象(重命名 getter)
...mapGetters({
discount: 'currentDiscount' // 将 currentDiscount 映射为 discount
})
}
}
</script>

2,在 setup 函数中使用
(1)在 Vue 3 的 Composition API 中,mapGetters 返回的对象中的属性并不是计算属性,因此不能直接在模板中使用。
注意:mapGetters 返回的是普通函数对象,需要使用 computed 包装后才能变成响应式的计算属性。
(2)为了解决这个问题,我们需要封装一个自定义 Hook 函数。新建 src/hooks/useGetters.js 文件,改代码的目的是将 mapGetters 返回的普通函数转换成响应式的计算属性函数。
import { useStore, mapGetters } from 'vuex'
import { computed } from 'vue'
export function useGetters(mapper) {
const store = useStore()
// 1. 使用 mapGetters 辅助函数
const stateFns = mapGetters(mapper)
const state = {}
// 2. 遍历将普通函数转换成计算属性
Object.keys(stateFns).forEach(fnKey => {
// 绑定 $store 并包装成计算属性
state[fnKey] = computed(stateFns[fnKey].bind({ $store: store }))
})
return state
}
(3)接着,在 src/hooks/index.js 中统一导出:
import { useState } from './useState'
import { useGetters } from './useGetters'
export { useState, useGetters }
(4)最后,在组件中使用封装好的 useGetters:
<template>
<div>
<h4>书籍总价:{{ $store.getters.totalPrice }}</h4>
<h4>Vue.js 书籍总价:{{ totalPriceByName('Vue.js') }}</h4>
</div>
</template>
<script>
import { useGetters } from './hooks'
export default {
setup() {
// 调用自定义 Hook
const storeGetters = useGetters(['totalPriceByName'])
return {
...storeGetters
}
}
}
</script>
(6)保存代码后,在浏览器中便可查看效果,与直接使用 $store.getters 的效果一致。
全部评论(0)