多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] ## 1. 开始 vuex作为一个vue状态(数据)管理的管理模式。尤其在中大型前端应用中,多组件共享状态处理时应用效果最佳。 1. 组件发起事件 2. Actions接收到状态变化事件,commit一个Mutation(变化) 3. 导致state中数据变化,然后渲染都组件 ![](https://img.kancloud.cn/63/19/6319295167cb7d0694c1e41bd8647b78_759x538.png) * [ ] state:数据存储 * [ ] action:事件处理,可以写处理逻辑(可以异步),然后调用mutation * [ ] mutation:修改state中数据 ### 1.1 安装 **1.安装webpack** ~~~ npm i webpack -g ~~~ **2. 新建一个test工程** 再创建项目时,选择了store,router,所以有以下文件默认生成 ``` vue create test ``` ![](https://img.kancloud.cn/76/62/7662f91b63370dddea7cf4db0eda3bf2_782x471.png) ### **1.2 state数据获取** * [ ] 组件获取state中数据 1)this.$store.state.count 2)或者mapState辅助函数 ``` // computed: mapState({ //写法一 //   count: 'count',}) computed: { ...mapState([ 'count', //多个用逗号分开,写法二 ]), }, ``` **1. 构建一个store对象,并导出** 在vue cli创建的项目中,默认加载store目录下的index.js文件 **定义state对象,内涵数据count** ``` importVuefrom"vue"; importVuexfrom"vuex"; Vue.use(Vuex); exportdefaultnewVuex.Store({ state: { count:0,   }, mutations: {}, actions: {}, modules: {} }); ``` **2. main.js文件导入store** ``` import Vue from "vue"; import App from "./App.vue"; import router from "./router"; import store from "./store"; // 1.引入store Vue.config.productionTip = false; new Vue({ router, store, render: h => h(App) //将组件渲染到index.html }).$mount("#app"); ``` **3. app.vue中使用state中数据** 中通过计算属性关联state,在组件中通过 方法一、通过`this.$store.state.count` 使用数据 ``` <template> <div id="app"> <div id="nav"> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> <!-- 1.使用计算属性 --> <h1>count:{{count}}</h1> </div> <router-view /> </div> </template> <script> export default { computed: { count() { //2.获取state数据 return this.$store.state.count } } } </script> ``` **方法二,使用mapstate辅助函数获取state数据** app.vue组件中 ``` import { mapState } from'vuex' exportdefault { // computed:  //   //获取state数据方式一 //   count() { //     return this.$store.state.count //   } // } computed:mapState({ // 获取state数据方式二 count:'count',}) } ``` mapState还可以这么写 ``` computed: { ...mapState([ 'count', //多个用逗号分开 ]), }, ``` ### **1.3 mutation中方法触发** **mutation中的方法用于修改state中的值** 方式一、`$store.commit('mutationName')` 触发状态值的改变 方式二、mapMutations辅助函数进行映射,就是将vuex中的函数,映射到当前组件当中,通过this来调用 ``` methods: { // add() { // this.$store.commit('addcount',2) //触发mutation中方法,方式一 // } ...mapMutations({ 'add': 'addcount' // 将 `this.add()` 映射为 `this.$store.commit('addcount', n)` }) }, ``` 映射方法名相同可以简写 ``` ...mapMutations(['addcount']) ``` ![](https://img.kancloud.cn/77/9c/779c6d80cf1ae177e26dec5e3bc268fa_1122x467.png) **1. 在store的mutation中定义方法** ``` mutations: { addcount(state) { state.count ++ } }, ``` 2. vue.app中 ``` <!-- 1.使用计算属性 --> <h1>count:{{count}}</h1> <button @click="add"> 加一</button> methods: { add() { this.$store.commit('addcount') //触发mutation中方法 } }, ``` 也可以提交载荷,即为传参 ``` this.$store.commit('addcount',2) //app.vue 触发mutation中方法,每次加2 mutations: { addcount(state,n) { state.count +=n     }  }, ``` ![](https://img.kancloud.cn/14/08/1408054cb8356cf9fdba2863608c84e2_545x191.png) 写法二 ``` methods: { // add() { // this.$store.commit('addcount',2) //触发mutation中方法,方式一 // } // ...mapMutations({ // 'add': 'addcount' // 将 `this.add()` 映射为 `this.$store.commit('addcount', n)` // }) ...mapMutations(['addcount']) // //触发mutation中方法,方式二,如果映射的方法名相同,则可以如此简写 }, ``` ### 1.4 action **Action 类似于 mutation,不同在于:** * Action 提交的是 mutation,而不是在组件中直接变更状态, 通过它间接更新 state(action可以写一下逻辑业务处理)。 * 在组件中通过 this.$store.dispatch('actionName') 触发状态值间接改变 * Action 也支持载荷 * Action 可以包含任意异步操 1. 在store中index.js添加函数 ``` actions: { add(context, n) { context.commit('addcount',n)     }, decrement({commit,state},n){ //es6写法,直接从context中获取commit commit('decrementcount',n)     }   }, ``` 2. app.vue 中 方法中映射action函数 ``` <template> <div id="app"> <div id="nav"> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> <!-- 1.使用计算属性 --> <h1>count:{{count}}</h1> <!-- <button @click="addcount(2)"> 加一</button> --> <button @click="add(2)">加二</button> <button @click="decrement(3)">减三</button> </div> <router-view /> </div> </template> import { mapState,mapMutations, mapActions } from'vuex' exportdefault { methods: { // add() { //   this.$store.commit('addcount',2) //触发mutation中方法,方式一 // } // ...mapMutations({ //     'add': 'addcount'  // 将 `this.add()` 映射为 `this.$store.commit('addcount', n)` //   })    ...mapMutations(['addcount']), // //触发mutation中方法,方式二,如果映射的方法名相同,则可以如此简写    ...mapActions(['add','decrement'])   }, } ``` ### 1.3 派生属性getter 1. 当需要从 store 中的 state 中派生出一些状态。 例如:count值大于10,显示加多了,大于12显示加太多了。这时我们就需要用到 getter 为我们解决。 2. getter 其实就类似于计算属性(get)的对象. 3. 组件中读取 $store.getters.xxx store/index.js ``` getters: { desc(state) { if (state.count > 10 && state.count <= 12) { return '加多了' } else if (state.count > 12) { return '加太多了' } else { return '加的一般' } } } ``` app.vue 写法一,`$store.getters.xxx`获取值 ``` <template> <div id="app"> <div id="nav"> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> <!-- 1.使用计算属性 --> <h1>count:{{count}}</h1> <!-- <button @click="addcount(2)"> 加一</button> --> <button @click="add(2)">加二</button> <button @click="decrement(3)">减三</button> getter-desc:{{$store.getters.desc}} </div> <router-view /> </div> </template> ``` ![](https://img.kancloud.cn/66/37/66375b98f63fb12a9100e530edd20078_403x257.png) **写法二,通过mapGetters辅助函数获取值** ``` getter-desc:{{desc}} // app.vue首先引入mapGetters import { mapState,mapMutations, mapActions,mapGetters } from 'vuex' computed: { ...mapState([ 'count', //多个用逗号分开 ]), ...mapGetters(['desc']) }, ``` ### 1.4 子组件中如何获取值 ![](https://img.kancloud.cn/e4/47/e4473284b04e25cda9450f0a6fd2e7d1_625x445.png) 如上图,home和about如何获取state中的值呢? 一、组件传值肯定是可以的 子组件props声明一下 ``` props:['count'] ``` 父组件 ``` <子组件 :count="count"></子组件> computed: { ...mapState([ 'count', //多个用逗号分开 ]), ...mapGetters(['desc']) }, ``` 2. 通app.vue组件一样,获得vuex状态 ``` <template> <div class="about"> <h1>This is an about page</h1> <h1>about组件:{{count}}</h1> </div> </template> <script> import { mapState, mapGetters } from "vuex"; export default { computed: { ...mapState([ "count" //多个用逗号分开 ]), ...mapGetters(["desc"]) } }; </script> ``` ![](https://img.kancloud.cn/57/ec/57ecf3648ed64264e2b87553b3ecc0fe_853x424.png) ## **2. state的值与input和select表单绑定** **vuex 强调的是Unidirection Dataflow,state中数据应该只能被读取,写入应该由mutation完成。** 因此通过v-model绑定state值,并通过表单元素进行修改,是不建议的,当然可以成功改变,但是控制台会输出错误信息,如下: ~~~ <el-form-item prop="rdn"> <el-col :span="12"> <el-input v-model="currentOrg.rdn" placeholder="" size="small" @input="cnKeyUp"></el-input> </el-col> </el-form-item> computed: { ...orgState({currentOrg: 'current', orgItems: 'items', tmpData: 'tmpData'}), isNew() { return Boolean(this.currentOrg && this.currentOrg.id); }, ~~~ ``` vue.js:1897 Error: [vuex] do not mutate vuex store state outside mutation handlers. at assert (vuex.esm.js?be43:90) at Vue.store._vm.$watch.deep (vuex.esm.js?be43:793) at Watcher.run (vue.js:4561) at Watcher.update (vue.js:4535) at Dep.notify (vue.js:745) at Object.reactiveSetter [as rdn] (vue.js:1070) at Proxy.set (vue.js:1091) at callback (eval at ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"d1305b30-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/parts/system/org/org-tabs.vue?vue&type=template&id=12c5e28c&scoped=true& (xms_user.js:4808), <anonymous>:62:45) at invokeWithErrorHandling (vue.js:1863) at VueComponent.invoker (vue.js:2184) ``` ### **2.1 通过computed的set和get解决** computed中计算数据 1. get从vuex中获取数据 2. set调用mutation修改数据 ~~~ <template> <div> <div> <input type="text" v-model="name"> </div> <div> {{ name }} </div> </div> </template> <script> /** computed */ const name = { get() { return this.$store.state.name; }, set(value) { this.$store.commit('setName', value); }, }; const computed = { name, }; export default { name: 'HelloWorld', computed, }; </script> ~~~ ### 2.2 组件mounted时,深拷贝 ~~~ <el-form :model="currentOrgIns" ref="orgForm" :inline="true" label-position="left" class="demo-form-inline" label-width="90px" :rules="rules"> <el-form-item label="机构类别" prop="type"> <el-select v-model="currentOrgIns.type" placeholder="请选择加密设备" size="small" @change="typeChange"> <el-option label="CA" value="ca"></el-option> <el-option label="RA" value="ra"></el-option> </el-select> </el-form-item> <el-form-item label="额外属性" prop="dnAttrCo"> <el-input v-model="currentOrgIns.dnAttrCo" placeholder="" size="small"></el-input> </el-form-item> <el-form-item label="备注" prop="roMemo"> <el-input v-model="currentOrgIns.roMemo" placeholder="" size="small"></el-input> </el-form-item> </el-form> import _ from "lodash"; data() { return { currentOrgIns: {}, }, // 组件mounted后,将state中的数据currentOrg深拷贝给data中数据 async mounted() { this.currentOrgIns = _.cloneDeep(this.currentOrg); }, computed: { ...orgState({currentOrg: 'current', orgItems: 'items', tmpData: 'tmpData'}), }, ~~~ # vuex中action和mutations (this.$store.dispatch和this.$store.commit)的区别 dispatch:含有异步操作,例如向后台提交数据,写法: this.$store.dispatch('action方法名',值) commit:同步操作,写法:this.$store.commit('mutations方法名',值) action: 1、用于通过提交mutation改变数据 2、会默认将自身封装为一个Promise 3、可以包含任意的异步操作 mutations: 1、通过提交commit改变数据 2、只是一个单纯的函数 3、不要使用异步操作,异步操作会导致变量不能追踪。也就是说,用action中的函数调用mutations中的函数,进行异步操作state中的数据