1、思想:基于响应式的原理:所有的状态的变更都是因为数据的变化引起的
。
2、背景:在传统的vue应用中,我们可能定义许多component
,而每个component可能是这样的:
var component_library_title = {
props: ['text'],
data:{
a:'',
b:''
},
template: '<div>{{text}}</div>'
};
这样,在不用的component中,就会出现属于不用vue的组件管理的data数据,这样,如果在父子component或者兄弟component中进行数据传递的时候,会比较混乱。
3、解决:将所有的data交给vuex管理。
- 如何获取数据:
因为在vue的computed
钩子中,其中的方法会在管理的数据源发生变更的时候,主动调用并更新数据,所以这样正好,我们可以知道vuex管理的store发生变更的时候,数据如何变化。
- 如何更改数据:
通过commit或者dispatch去发送事件更改数据源,而不建议直接调用类似store.data.a
去更改数据。
核心概念
State
单一状态树:一个应用只对应一个状态树,且这种思想和组件化并不冲突!
1、将State注册到所有的子组件中
const app = new Vue({
el: '#app',
// 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
store,
components: { Counter },
template: `
<div class="app">
<counter></counter>
</div>
`
})
如果想直接访问store实例中的属性,可以这样:this.$store.state.属性
进行访问。
2、使用mapState
3、在子component中使用store中的state
你需要在子component
中的computed
钩子中创建方法
computed: {
count () {
return this.$store.state.count
}
}
然后在需要使用的地方,直接{{count}}
就可以了。
Getters
其实是一种规范吧:
本来我们在子component中就能够通过如上的方法获取store的state的属性,但是,假设我们希望对直接定义在store中的属性进行一些操作(这里官方网站说的是一些filter操作等),我们希望不要再修改
mapState
或者直接通过return this.$store.state.count
来进行数据的获取或者修改。于是就使用
getter
进行数据的操作并装换。注意到,我们在修改一个的时候,可能需要同时和其他的store中的state下面的数据进行以前操作,这就意味着,我们需要拿到
state
这个对象。而的确是这样的,getters中允许我们在定义的方法中带有
state
参数
1、定义
getters: {
count(state){
return state.count + 1;
},
}
2、使用
computed: {
getMessage(){
return this.$store.state.count;
},
}
你需要在子component中的computed
钩子中定义方法,这样就能直接使用了。
Mutations
我们会返现,在Vuex
中,只有Getter
的定义,而没有类似于Setter
的定义.
其实,这里的Mutations
就是Setter
的实现.
虽然我们能够通过this.$store.state.属性
获取到某个属性,并进行修改,但是,vuex强烈建议我们不要这样做。
1、直接修改在$store.state
中的值
我们直接在子component中定义了一个方法,用来直接$store.state
中的值。
- html中
template: '<div>{{getMessage}}并且:{{getMessage1}}' +'<button @click="changeMessage">修改</button>' +'</div>',
- js中
methods: {
changeMessage(){
console.log(this.$store.state.count);
this.$store.state.count = 100;
}
}
我们发现,在调用changeMessage
后,this.$store.state.count
变成了100。
说明我们本身是能够直接调用this.$store.state.count
进行state中值得修改的。
Note:但是,Vuex建议我们不要这样做,如果需要修改
this.$store.state
中的值,建议在store中的Mutations
钩子中进行方法的定义来完成。
2、使用Mutations
mutations: {
increment (state) {
// 变更状态
state.count++
}
}
注意在定义方法的时候,可以携带state
参数。
3、触发方法
方法一:使用方法名称
在本component中
store.commit('方法名称');
在子component中
this.$store.commit('方法名称');
方法二:使用对象
store.commit({
type:'方法名称',
...
});
4、使用常量定义mutations中的方法名
mutations: {
[INCREMENT](state){
state.count++;
},
[DECREMENT](state){
state.count--;
},
},
这样,就会比较方便的进行管理了。
Actions
顾名思义,这也是一个可以改变state中属性的方法集。但是mutations中不是已经提供了可用的方法集合了嘛?!
但是,如果你在Mutations中写就的方法集合中某个方法是异步的,那么我们不建议将异步方法写在Mutations
中(虽然的确是可以的)。
那么,我们需要将这些方法写在Actions
中。
1、写法
actions: { asyncIncrement(context){ console.log('asyncIncrement'); context.commit('INCREMENT'); }}
2、调用
这里称之为“分发”。
asyncIncrement(){
store.dispatch({
type: 'asyncIncrement',
amount: 4,
});
}
3、在模块中分发消息
changeMessageAsync(){
console.log('异步修改');
this.$store.dispatch('asyncIncrement')
}
这样,直接使用this.$store.dispatch('asyncIncrement')
进行分发。
表单操作
传统方法(不按照Vuex的思路去管理数据)
Vuex的思维方式:我们需要将数据统一管理,使用computed
时刻观察数据的变化,并通过commit
或者dispatch
的方式改变数据。
那么我们只需要使用v-model
就能方便简单的实现了。
但是一旦我们在某处使用了vuex,并且我们希望在任何地方也使用vuex的思维进行数据的管理。
那么问题就来了。
- 问题来了:
<input type="text" v-model="bookSerialNumber"/>
computed:{ bookSerialNumber(){
return this.$store.state.book.serialNumber;
},
},
我们只能通过计算属性(computed)计算出当前this.$store.state.book.serialNumber
的值,而无法实现该值的修改。
除非我们在方法
bookSerialNumber
中通过直接改变this.$store.state.book.serialNumber
的值,但是这样是明显不符合vuex方法论的。
vuex的解决
<input type="text" @input='bookNameInputChange' :value='bookName'/>
为你的表单中的某一项:
- 使用
:value
单向绑定某个在computed
中实现的计算属性; - 使用
@input
监听控件的输入的变化,这样就实现了setter的方法,我们通过在mutations
中定义的属性对属性进行控制,假设这个改变的过程是异步的,你需要在actions
中定义属性,并通过dispatch
进行事件的分发。
vue的方法论
- 通过
state
设置元(原)数据; - 通过
getters
设置访问元数据的属性(function),一般这里的属性是逻辑是直接获取原属性,不再做其他的操作; - 通过
mutations
设置改变元数据的属性(function),并且约定这里的方法都是同步适宜的。 - 通过
actions
设置改变元数据的异步方法。