简介
说明
本文用示例介绍Vue的vuex的组件绑定的辅助函数的用法。包括:mapState, mapGetters, mapActions, mapMutations。
官网
State | Vuex
API 参考 | Vuex
示例
公共代码
需求:点击一个组件按钮,增加另一个组件的数量。
router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import CompA from "@/components/CompA";
Vue.use(Router)
export default new Router({
routes: [
{
path: '/compA',
name: 'compA',
component: CompA,
}
],
})
store/CounterStore.js //计数器store
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const couterStore = new Vuex.Store(
{
state: {
count1: 0
},
mutations: {
incr1(state) {
state.count1++;
},
decr1(state) {
state.count1--;
},
},
}
);
export default couterStore;
components/CompA.vue
因为vue是单页面应用,所以用此组件引入其余两个组件。
<template>
<div class="compA">
<child-one></child-one>
<hr>
<child-two></child-two>
</div>
</template>
<script>
import ChildOne from "@/components/ChildOne";
import ChildTwo from "@/components/ChildTwo";
export default {
components: {ChildOne, ChildTwo},
data() {
return {
}
},
}
</script>
<style scoped>
</style>
components/ChildOne.vue //发送事件
<template>
<div class="childOne">
<h1>childOne</h1>
<button @click="incr1">增加:兄弟组件(ChildTwo)</button>
<button @click="decr1">减少:兄弟组件(ChildTwo)</button>
</div>
</template>
<script>
export default {
data() {
return {
payload: {
amount: 5
}
}
},
methods:{
incr1() {
this.$store.commit('incr1')
},
decr1() {
this.$store.commit('decr1')
},
}
}
</script>
<style scoped>
</style>
components/ChildTwo.vue //接收事件
<template>
<div class="childTwo">
<h1>childTwo</h1>
收到的事件内容:{{msg}}
</div>
</template>
<script>
export default {
data() {
return {
}
},
computed:{
msg() {
return this.$store.state.count1;
}
}
}
</script>
<style scoped>
</style>
测试
访问:http://localhost:8080/#/compA
mapState
简介
当一个组件需要获取多个状态时,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,可以使用mapState辅助函数帮助生成计算属性
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// 箭头函数可使代码更简练
count: state => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
// 下边这行等价于: countAlias: state => state.count
countAlias: 'count',
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
当映射的计算属性的名称与 state 的子节点名称相同时,也可以给 mapState 传一个字符串数组
computed: mapState([
// 映射 this.count 为 store.state.count
'count'
])
//等价于
//computed: {
// count(){
// return this.$store.state.count
// }
//}
改造“公共代码”
<template>
<div class="childTwo">
<h1>childTwo</h1>
收到的事件内容:{{msg}} <br>
count1Alias: {{count1Alias}} <br>
事件加本地值: {{countPlusLocalState}} <br>
</div>
</template>
<script>
import {mapState} from 'vuex'
export default {
data() {
return {
localCount: 5,
cnt: 0
}
},
// 原来的写法
// computed:{
// msg() {
// return this.$store.state.count1;
// }
// }
computed: mapState({
msg: state => state.count1,
//上边这行也可以这么写:
//msg: 'count1'
count1Alias: 'count1',
countPlusLocalState(state) {
return this.msg + this.localCount
}
})
}
</script>
<style scoped>
</style>
测试
访问:http://localhost:8080/#/compA
mapGetters
简介
mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
如果想将一个 getter 属性另取一个名字,使用对象形式:
mapGetters({
// 映射 `this.doneCount` 为 `store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
改写“公共代码”
store/CounterStore.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const couterStore = new Vuex.Store(
{
state: {
count1: 0
},
mutations: {
incr1(state) {
state.count1++;
},
decr1(state) {
state.count1--;
},
},
getters: {
doubleCount1: state => {
return state.count1 * 2;
}
}
}
);
export default couterStore;
components/ChildTwo.vue
<template>
<div class="childTwo">
<h1>childTwo</h1>
收到的事件内容:{{msg}} <br>
doubleCount1: {{doubleCount1}}
</div>
</template>
<script>
import {mapGetters} from 'vuex'
export default {
data() {
return {
}
},
computed:{
msg() {
return this.$store.state.count1;
},
...mapGetters(['doubleCount1'])
// 也就是:
// doubleCount1() {
// return this.$store.getters.doubleCount1;
// }
}
}
</script>
<style scoped>
</style>
测试
访问:http://localhost:8080/#/compA
mapMutations
简介
可以在组件中使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
})
}
}
改造“公共代码”
<template>
<div class="childOne">
<h1>childOne</h1>
<button @click="incr1">增加:兄弟组件(ChildTwo)</button>
<button @click="decr1">减少:兄弟组件(ChildTwo)</button>
</div>
</template>
<script>
import {mapMutations} from 'vuex'
export default {
data() {
return {
payload: {
amount: 5
}
}
},
methods: {
// 原来的写法
// incr1() {
// this.$store.commit('incr1')
// },
// decr1() {
// this.$store.commit('decr1')
// },
...mapMutations(['incr1', 'decr1'])
}
}
</script>
<style scoped>
</style>
测试
访问: http://localhost:8080/#/compA
使用别名映射
<template>
<div class="childOne">
<h1>childOne</h1>
<button @click="incrAlias">增加:兄弟组件(ChildTwo)</button>
<button @click="decrAlias">减少:兄弟组件(ChildTwo)</button>
</div>
</template>
<script>
import {mapMutations} from 'vuex'
export default {
data() {
return {
}
},
methods: {
...mapMutations({incrAlias: 'incr1', decrAlias: 'decr1'})
}
}
</script>
<style scoped>
</style>
测试
访问: http://localhost:8080/#/compA
数组与别名同时使用
<template>
<div class="childOne">
<h1>childOne</h1>
<button @click="incr1">增加:兄弟组件(ChildTwo)</button>
<button @click="decrAlias">减少:兄弟组件(ChildTwo)</button>
</div>
</template>
<script>
import {mapMutations} from 'vuex'
export default {
data() {
return {
}
},
methods: {
...mapMutations({...mapMutations(['incr1']), ...{decrAlias: 'decr1'}})
}
}
</script>
<style scoped>
</style>
测试
访问: http://localhost:8080/#/compA
mapActions
简介
在组件中使用 this.$store.dispatch('xxx') 分发 action,或者使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用。
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
// `mapActions` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
]),
...mapActions({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
})
}
}
改写“公共代码”
store/CounterStore.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const couterStore = new Vuex.Store(
{
state: {
count1: 0
},
mutations: {
incr1(state) {
state.count1++;
},
decr1(state) {
state.count1--;
},
},
actions: {
incr1Async(context) {
setTimeout(() => {
context.commit('incr1')
}, 1000)
},
decr1Async(context) {
setTimeout(() => {
context.commit('decr1')
}, 1000)
}
}
}
);
export default couterStore;
components/ChildOne.vue
<template>
<div class="childOne">
<h1>childOne</h1>
<button @click="incr1">增加:兄弟组件(ChildTwo)</button>
<button @click="decr1">减少:兄弟组件(ChildTwo)</button>
<button @click="incr1Async">异步增加:兄弟组件(ChildTwo)</button>
<button @click="decr1Async">异步减少:兄弟组件(ChildTwo)</button>
</div>
</template>
<script>
import {mapActions} from 'vuex'
export default {
data() {
return {
}
},
methods: {
incr1() {
this.$store.commit('incr1');
},
decr1() {
this.$store.commit('decr1');
},
...mapActions(['incr1Async', 'decr1Async']),
}
}
</script>
<style scoped>
</style>