vuex commit 模块_Vuex详细介绍
1. 什么是VuexVuex 是一个专为 Vue.js 应用程序开发的状态管理模式。这是官网的说法,其实很简单:就是一个加强版的data! 在单页应用中会有一个data函数,里面就存放了当前页面的一些数据。比如:<template><div><p>{{num}}</p></div></temp...
1. 什么是Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。这是官网的说法,其实很简单:就是一个加强版的data! 在单页应用中会有一个data函数,里面就存放了当前页面的一些数据。比如:
<template>
<div>
<p>{{num}}</p>
</div>
</template>
<script>
export default {
data(){
return {
num:'99'
}
}
}
</script>
代码中的data就相当于我们这里描述的Vuex。 如果我们的页面比较简单,切记千万不要没事找事引入Vuex,我们使用Vuex是因为项目变得复杂之后,有很多数据需要在父组件、子组件和孙组件之间传递,处理起来很繁琐,于是就需要Vuex这样一个可以对这一部分数据进行统一管理的东西。
2. 全局data就行了,非要这么复杂?
对于我刚刚提到的需求:处理大量的需要在组件间传递的数据,直接定义一个全局的data属性保存就行了,比如这样:this.$root.$data
。为什么还要搞一个这么复杂的状态管理? 如果我们按照刚刚所说的搞一个全局变量存放数据其实也行,但是这样有一个问题,就是数据改变后,不会留下变更过的记录,这样不利于调试。 所以我们稍微搞得复杂一点。我们约定组件不能直接修改属于store实例的state,组件必须通过Mutation来改变state,也就是说,组件里面应该执行分发(dispatch)事件通知store去改变。这样约定的好处是,我们能够记录所有store中发生的state改变,同时实现能做到记录变更、保存状态快照、历史回滚/时光旅行的先进的调试工具。
3. 先来一个简单的State
知道了个大概,那我们就实际操作一遍,感觉一下这个听起来很牛逼的东西用起来到底怎么样。 我们使用vue-cli脚手架生成一个Vue项目,并且安装Vuex,最终的项目结构是这样的:
我们在components里面新建一个组件,然后加入以下代码:
<p>{{ count }}</p>
<div>
<p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</p>
</div>
methods:{
increment(){
},
decrement(){
},
},
接着新建一个vuex文件夹,里面新建一个store.js文件,并加入以下代码:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 应用初始状态
const state = {
count: 0,
}
// 创建 store 实例
export default new Vuex.Store({
state,
})
然后我们在组件中就可以使用我们的count变量了:
computed:{
count(){
return this.$store.state.count;
},
}
我们定义一个计算属性,返回store中的count变量:
3. 计算属性?引入Getter
这里我们可以假想一个场景,我们的页面中现在显示的数字是0,如果我们的需求是这样的,页面中数字如果小于10,就显示为00。那我们可以在刚刚的组件中将计算属性返回的值修改成这样:
return this.$store.state.count > 9 ? this.$store.state.count : '0'+this.$store.state.count;
就可以了,但是如果我们有很多组件都使用了这个count的话,那我们在每一个使用这个变量的地方都需要写一遍这个判断,那为什么不在取数据的时候就把数据整理成想要的样子呢?就和我们组件中的计算属性一样!为了达到目的,我们修改一下store.js:
import Vue from 'vue'
import Vuex from 'vuex'
import * as getters from './getters' //新增
Vue.use(Vuex)
// 应用初始状态
const state = {
count: 0,
}
// 创建 store 实例
export default new Vuex.Store({
state,
getters //新增
})
然后我们新建一个getters.js文件:
export const countaddzero = state => {
return state.count > 9 ? state.count : '0' + state.count;
}
最后我们改一改组件中的计算属性:
return this.$store.getters.countaddzero;
保存之后发现页面上的数字果然变成了00。
4. 试试修改State,引入Mutation
我们的本意是要做一个点击按钮数字可以增加的一个小demo,现在把数据存到store是完成了。接下来说一下如何修改数据。 为了方便查看,我们先修改一下store.js这个文件:
import Vue from 'vue'
import Vuex from 'vuex'
import * as getters from './getters'
Vue.use(Vuex)
// 应用初始状态
const state = {
count: 0,
}
// 定义所需的 mutations //新增
const mutations = { //新增
increment(state, val = 1) { //新增
state.count += val; //新增
}, //新增
decrement(state, val = 1) { //新增
state.count -= val; //新增
} //新增
} //新增
// 创建 store 实例
export default new Vuex.Store({
state,
getters,
mutations //新增
})
其中的val表示点击按钮每次需要增加(减少)多少。 有了mutations我们就可以在组件中对store里面的state进行修改了,我们先处理一下组件中的点击事件,当点击加或者减按钮的时候才去修改store里面的值。我们修改一下组件的methods:
methods:{
increment(){
this.$store.commit('increment',2); //新增
},
decrement(){
this.$store.commit('decrement',2); //新增
},
},
其中的2就是之前提到的每一次增加多少,也就是前文的val。我们约定只能通过commit的方式修改store的变量,为什么说是预定呢?手贱的我决定试试:
methods:{
increment(){
// this.$store.commit('increment',2); //修改
this.$store.state.count=1000; //新增
},
},
其实这样也可以修改store里面的值,但是这样就不能达到我们刚开始所说的目的了。 一条重要的原则就是要记住mutation必须是同步函数。因为我们不知道什么时候回调函数实际上被调用——实质上任何在回调函数中进行的状态的改变都是不可追踪的。
5. 异步修改?引入Action
那如果我们就想异步的修改store的值呢?也是有办法的,这时候就需要我们的Action出场了: Action 类似于 mutation,不同在于:
Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。
我们还是先改改代码,我们新建一个actions.js:
export const incrementAsync = ({ commit }, val = 1) => {
setTimeout(() => {
commit('increment', val)
}, 1000)
}
export const decrementAsync = ({ commit }, val = 1) => {
setTimeout(() => {
commit('decrement', val)
}, 1000)
}
这里我们使用setTimeout模拟一下异步执行。接着修改我们的组件
<p>
异步:
<button @click="increment2">+</button>
<button @click="decrement2">-</button>
</p>
修改一下methods:
methods:{
increment2(){
this.$store.dispatch('incrementAsync',2);
},
decrement2(){
this.$store.dispatch('decrementAsync',2);
},
},
Action通过store.dispatch
方法触发,乍一眼看上去感觉多此一举,我们直接分发mutation岂不更方便?实际上并非如此,还记得mutation必须同步执行这个限制么?Action 就不受约束!我们可以在 action 内部执行异步操作。 最后修改一下store.js文件: 在顶部导入actions:import * as actions from './action'
然后在实例化的时候加入actions:
// 创建 store 实例
export default new Vuex.Store({
actions, //新增
getters,
state,
mutations
})
这样就可以实现异步修改store啦!
6. 不方便维护?引入Module
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。 为了解决以上问题,Vuex允许我们将store分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
7. 一点点注意事项
当在严格模式中使用 Vuex 时,在属于 Vuex 的 state 上使用 v-model 会比较棘手:
<input v-model="obj.message">
假设这里的 obj 是在计算属性中返回的一个属于Vuex store的对象,在用户输入时,v-model会试图直接修改obj.message。在严格模式中,由于这个修改不是在 mutation 函数中执行的, 这里会抛出一个错误。 也就是说其实双向数据绑定和vuex是会有一点冲突的,不过化解的方法也有: 第一种方法: 给 中绑定 value,然后侦听input或者change事件,在事件回调中调用 action:
<input :value="message" @input="updateMessage">
也就是不实用v-model。 第二种方法: 双向绑定的计算属性
<input v-model="message">
computed: {
message: {
get () {
return this.$store.state.obj.message
},
set (value) {
this.$store.commit('updateMessage', value)
}
}
}
更多推荐
所有评论(0)