vue3中使用vuex

1、注入store

使用Vue3、Vuex4版本,通过如下方式向注入store,

import { createApp } from 'vue';
import App from './App.vue';
import {createStore} from 'vuex';

const store = createStore({
  state: {
    counter: 0
  },
  getters: {
    counter10times(state) {
      return state.counter * 10;
    }
  },
  mutations: {
    increaseCounter(state) {
      state.counter++;
    }
  },
  modules: {
    a: {
      namespaced: true,
      state: {aName: 'A·a'},
      getters: {
        aFirstName(state) {
          return state.aName.split('·')[0];
        }
      },
      mutations: {
        changeAName(state) {
          state.aName = 'A-a';
        }
      },
      actions: {
        callChangeCNameAsync({dispatch}) {
          // 触发子模块的action,相对与自身的路径
          setTimeout(() => {
            dispatch('c/changeCNameAsync');
          }, 500);
        }
      },
      modules: {
        c: {
          namespaced: true,
          state: {cName: 'C·c'},
          getters: {
            cFirstName(state) {
              return state.cName.split('·')[0];
            }
          },
          mutations: {
            changeCName(state, payload) {
              state.cName = `C-c-${payload.suffix}`;
            }
          },
          actions: {
            changeCNameAsync({commit, rootState}) {
              setTimeout(() => {
                // 提交其他模块的mutation,mutation是全局的
                commit('increaseCounter', null, {root: true});
                // 提交局部模块的mutation,不需要加前缀
                commit('changeCName', {
                  suffix: rootState.counter
                });
              }, 500);
            }
          }
        }
      }
    },
    b: {
      namespaced: true,
      state: {bName: 'B·b'},
      getters: {
        bNewName(state, getters, rootState, rootGetters) {
          // 局部state
          const bName = state.bName.split('·')[0];
          // 其他模块的getter
          const cFirstName = rootGetters['a/c/cFirstName'];
          // 其他模块的state
          const aName = rootState.a.aName;
          return `${bName} ${cFirstName} ${aName}`;
        }
      },
      mutations: {
        changeBName(state) {
          state.bName = 'B-b';
        }
      }
    }
  }
});

createApp(App).use(store).mount('#app');
  1. 将刚才的加了命名空间的store注入到Vue组件树中。这样在所有的Vue组件中,都能够通过this.$store方式访问store。
  2. Vue组件通过computed属性来监听store的数据变化。

看下面的示例,computed依赖了this.$store里面的一些模块的state和getters,并将计算结果展示在界面上。

<template>
  <div>
    {{counter}}
    {{bName}}
    {{cFirstName}}
  </div>
</template>

<script>
  export default {
    computed: {
      counter() {
        return this.$store.state.counter;
      },
      bName() {
        return this.$store.state.b.bName;
      },
      cFirstName() {
        return this.$store.getters['a/c/cFirstName'];
      }
    }
  }
</script>

<style>
  #app {
    margin-top: 60px;
  }
</style>

下面看下Vue组件中改变状态的示例,

可以看到Vue组件中通过methods方法调用this.$store的commit和dispatch方法来提交修改和触发action。

/**
* @file main.js
*/
import { createApp } from 'vue';
import App from './App.vue';
import {createStore} from 'vuex';

const store = createStore({
    state: {
        counter: 0
    },
    getters: {
        counter10times(state) {
            return state.counter * 10;
        }
    },
    mutations: {
        increaseCounter(state) {
            state.counter++;
        }
    },
    modules: {
        a: {
            namespaced: true,
            state: {aName: 'A·a'},
            getters: {
                aFirstName(state) {
                    return state.aName.split('·')[0];
                }
            },
            mutations: {
                changeAName(state) {
                    state.aName = 'A-a';
                }
            },
            actions: {
                callChangeCNameAsync({dispatch}) {
                    // 触发子模块的action,相对于自身的路径
                    setTimeout(() => {
                        dispatch('c/changeCNameAsync');
                    }, 500);
                }
            },
            modules: {
                c: {
                    namespaced: true,
                    state: {cName: 'C·c'},
                    getters: {
                        cFirstName(state) {
                            return state.cName.split('·')[0];
                        }
                    },
                    mutations: {
                        changeCName(state, payload) {
                            state.cName = `C-c-${payload.suffix}`;
                        }
                    },
                    actions: {
                        changeCNameAsync({commit, rootState}) {
                            setTimeout(() => {
                                // 提交其他模块的mutation,mutation是全局的
                                commit('increaseCounter', null, {root: true});
                                // 提交局部模块的mutation,不需要加前缀
                                commit('changeCName', {
                                    suffix: rootState.counter
                                });
                            }, 500);
                        }
                    }
                }
            }
        },
        b: {
            namespaced: true,
            state: {bName: 'B·b'},
            getters: {
                bNewName(state, getters, rootState, rootGetters) {
                    // 局部state
                    const bName = state.bName.split('·')[0];
                    // 其他模块的getter
                    const cFirstName = rootGetters['a/c/cFirstName'];
                    // 其他模块的state
                    const aName = rootState.a.aName;
                    return `${bName} ${cFirstName} ${aName}`;
                }
            },
            mutations: {
                changeBName(state) {
                    state.bName = 'B-b';
                }
            }
        }
    }
});

createApp(App).use(store).mount('#app');
/**
* @file App.vue
*/
<template>
    <div>
        {{counter}}
        {{bName}}
        {{cFirstName}}
        <button @click="modifyBName">修改b的name</button>
        <button @click="modifyCName">修改c的name</button>
    </div>
</template>

<script>
export default {
    computed: {
        counter() {
            return this.$store.state.counter;
        },
        bName() {
            return this.$store.state.b.bName;
        },
        cFirstName() {
            return this.$store.getters['a/c/cFirstName'];
        }
    },
    methods: {
        modifyBName() {
            this.$store.commit('b/changeBName');
        },
        modifyCName() {
            this.$store.dispatch('a/callChangeCNameAsync');
        }
    }
}
</script>

<style>
#app {
    margin-top: 60px;
}
</style>

2、辅助函数

我们知道我们使用Vuex时候,通过computed绑定store的state和getters的数据,通过methods中调用this.$store的commit和dispatch方法来改变状态。

但是每次都要写this.$store,当需要绑定的数据多的时候会比较繁杂,因此Vuex提供了辅助函数来简化代码。辅助函数包括

vue3中使用vuex_第1张图片
vue3中使用vuex_第2张图片

<template>
    <div>
        {{counter}}
        {{bName}}
        {{counter10times}}
        {{cFirstName}}
        <button @click="modifyBName">修改b的name</button>
        <button @click="modifyCName">修改c的name</button>
    </div>
</template>

<script>
import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'

export default {
    computed: {
        ...mapState({
                        // 将this.$store.state.counter映射为counter
            counter: state => state.counter,
            // 也可以这样实现
            // counter: 'counter',
            bName: state => state.b.bName
        }),
        // 全局的getters
        ...mapGetters(['counter10times']),
        // 也可以这样实现,指定组件中的数据名称
        // ...mapGetters({
        //     counter10times: 'counter10times'
        // }),
        // 子模块的getters
        ...mapGetters({
            cFirstName: 'a/c/cFirstName'
        }),
        // 带有命名空间的子模块也可以这样实现映射,在方法多的时候可以简化代码
        // ...mapGetters('a/c', [
        //     'cFirstName'
        // ])
    },
    methods: {
        // 映射mutations到方法
        ...mapMutations({
            modifyBName: 'b/changeBName'
        }),
        // 也可以这样实现
        // ...mapMutations('b', {
        //     modifyBName: 'changeBName'
        // }),
        // 带有命名空间的子模块映射到组件的方法
        ...mapActions('a', {
            modifyCName: 'callChangeCNameAsync'
        }),
    }
}
</script>

<style>
#app {
    margin-top: 60px;
}
</style>

3、 组件之间共享数据

vue3中使用vuex_第3张图片

<template>
    <div>
        {{counter}}
        {{counter10times}}
        <b-child></b-child>
        <c-child></c-child>
        <button @click="modifyBName">修改b的name</button>
        <button @click="modifyCName">修改c的name</button>
    </div>
</template>

<script>
import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'
import bChild from './components/bChild';
import cChild from './components/cChild';

export default {
    computed: {
        ...mapState({
            counter: state => state.counter,
            // 也可以这样实现
            // counter: 'counter',
        }),
        // 全局的getters
        ...mapGetters(['counter10times']),
        // 也可以这样实现,指定组件中的数据名称
        // ...mapGetters({
        //     counter10times: 'counter10times'
        // }),
    },
    components: {
        'b-child': bChild,
        'c-child': cChild
    },
    methods: {
        // 映射mutations到方法
        ...mapMutations({
            modifyBName: 'b/changeBName'
        }),
        // 也可以这样实现
        // ...mapMutations('b', {
        //     modifyBName: 'changeBName'
        // }),
        // 带有命名空间的子模块映射到组件的方法
        ...mapActions('a', {
            modifyCName: 'callChangeCNameAsync'
        }),
    }
}
</script>

<style>
#app {
    margin-top: 60px;
}
</style>

转载于 https://www.jianshu.com/p/54608e9f93f2

你可能感兴趣的:(vuex,javascript,vue.js,前端)