有的时候我们会从后端获取一些下拉框选项的静态常量,而且很多页面都能用到,这个时候用Vuex是比较好的选择,涉及到后端获取,就要用到可以使用异步的actions了
src/store/modules/product.js
import {MU_PRODUCT_UPDATE_CONSTANTS} from '../../common/constants' const product = { state: { productConstants: [] }, mutations: { [MU_PRODUCT_UPDATE_CONSTANTS] (state, payload) { state.productConstants = payload } }, actions: { // action函数第一个参数接受一个与 store 实例具有相同方法和属性的 context 对象, // 因此你可以调用 context.commit 提交一个 mutation, // 或者通过 context.state 和 context.getters 来获取 state 和 getters // 这里虽然能获取到state,但是不建议直接修改state中的字段 async getProductConstants ({ commit }, payload) { try { // 请求接口,如果需要参数可以通过payload传递 const res = await this.$api.product.getConstants() commit(MU_PRODUCT_UPDATE_CONSTANTS, res) } catch (e) { console.error(e) } } }, getters: {} } export default product
下面触发这个getProductConstants事件,触发这个action事件的位置需要注意一下,假设你有5个组件需要使用这个state,那就应该在这5个组件共同的父组件中调用一次action(找不到就在根实例中调用),然后在各个子组件中通过mapState或mapGetters获取state,千万不要每个组件使用前都调用一次action方法!
src/App.vue
<!--为了更直观的展示action,把之前的代码删掉了--> <script> import { mapActions } from 'vuex' // 注意是mapActions export default { name: 'app', data () { return {} }, created () { // 触发请求 this.getProductConstants() } methods: { ...mapActions([ // 映射 this.getProductConstants 为 this.$store.dispatch('getProductConstants') 'getProductConstants' ]) } } </script>
mapGetters, mapMutations, mapActions,这几个函数可以接受对象也可以接受数组作为参数,如果你需要在组件中以别的名字调用该事件(像上面的mapMutations)就可以传入对象,key为新命名,value是store中定义的名字;否则的话传数组就好了。
那么问题来了,既然是异步操作,我想在操作结束后干点儿别的怎么做呢?
很简单,调用action中的异步函数(this.$store.dispatch)返回的是一个Promise,如果你跟我一样用的是async await:
<!--为了更直观的展示action,把之前的代码删掉了--> <script> import { mapActions } from 'vuex' // 注意是mapActions export default { name: 'app', data () { return {} }, async created () { // 触发请求 await this.getProductConstants() // 接下来执行的操作会等待上面函数完成才会执行 } methods: { ...mapActions([ // 映射 this.getProductConstants 为 this.$store.dispatch('getProductConstants') 'getProductConstants' ]) } } </script>
如果你用的不是async await那就麻烦一点,在actions中定义事件的时候return一个new Promise,官方文档中有一个例子
表单处理
当你把从state中获取的字段填在v-model中时,如果用户修改表单数据,v-model会尝试直接修改store中的数据,这样做会有两个问题:
破坏了vuex的数据传递规则,如果想修改state中的数据只能通过提交一个mutation
控制台报错:计算属性没有setter
官方提供了两种解决方法,我更倾向于下面这种,给计算属性添加setter,并在setter中提交mutation修改state:
<template> <input v-model="message"> </template> <script> export default { name: 'app', data () { return {} }, computed: { message: { get () { return this.$store.state.test.message }, set (value) { this.$store.commit('updateMessage', value) } } } methods: {} } </script>
Vuex持久化
推荐插件vuex-persist
安装插件:
npm install --save vuex-persist
引入、配置、加载插件:
src/store/persist.js
import VuexPersistence from 'vuex-persist' const persist = new VuexPersistence({ // 其他参数看文档 storage: window.sessionStorage }) export default persist.plugin
src/store/index.js
import ... import persist from './persist' Vue.use(Vuex) export default new Vuex.Store({ modules: { user, product, windowInfo }, plugins: [persist] })
现在刷新浏览器数据也不会重置了!
总结