Vuex:
本文只是对vuex官方文档的一点自己方式的"翻译",记录了vuex的一些基本概念及简单的使用。
Vuex:
--Vuex是什么?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
以上是vue官方很官方的解释简单的说:vuex是一个数据仓库,管理状态(数据)。
--什么时候使用Vuex:
Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。
如果您不打算开发大型单页应用(比如你的项目只有几页(组件)),那么使用 Vuex 可能是繁琐冗余的。
确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。
但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
还是很官方...简单的说就是必须使用:不使用项目会变得特别复杂或者做不下去了 的时候就是vuex出场的时候了。
1:Vuex的简单使用:
--1.1:安装vuex:
npm install vuex --save
--1.2:引入vuex:
在src下新建store文件夹,新建store.js文件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
--3:创建一个store数据仓库,并实例化vuex,export default 实例:
const state={
count:0
}
export default new Vuex.Store({
store
})
--4:在需要使用的page,引入store/store:
import store from '@/store/store'
export default {
name,
data(){},
store
}
--5:根据项目需求,读取状态/改变状态/操作状态
2:State:
Vuex使用单一状态树———用一个对象就包含了全部的应用层级状态。至此它便作为一个唯一数据源而存在。
这也意味着每个应用将仅仅包含一个store实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。
--如何在vue组件中获得vuex状态?
方式一:
在vue组件中引入store后通过:$store.state.name读取状态
方式二:
通过计算属性方式,简化读取:
comuted:{
count(){
return this.$store.state.count;
}
}
方式三:
通过mapState辅助函数:
当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题我们可以使用mapState辅助函数帮助我们生成计算属性;
1:首先在需要使用的组件中引入:
import { mapState} from 'vuex'
2:在组件计算属性中使用:
computed:mapState({
//使用箭头函数简化代码
count:state=>state.count
//传字符串参数:'count'等同于箭头函数:state=>state.count
countA:'count',
//如果要使用this获取局部状态,那么必须使用常规函数
countP(state){
return state.count + this.num
}
})
方式四:
通过mapState传入数组的形式获取状态:
computed:mapState(['count'])
3:Mutation:
更改vuex的store中的状态的唯一方法是提交mutation。
vuex中的mutation非常类似于事件:每个mutation都由一个字符串的事件类型(type)和一个回调函数(handler)。
这个回调函数就是我们实际进行状态更改的地方,并且它会接受state作为第一个参数。
需要注意的是:
我们不能直接调用一个mutation handler。这个选项更像是事件注册:
当触发一个类型为increment的mutation时,调用此函数。要唤醒一个mutation handler需要以相应的type调用store.commit()方法:
store.commit('increment')。
实例:
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 变更状态
state.count++
}
}
})
在需要调用的页面:@click="$store.commit('increment')"
--传递参数(提交载荷payload):
我们可以向store.commit传入额外的参数,即mutation的载荷(payload):
注1:mutations内的回调函数第一个参数为state。
注2:大多数情况下,载荷应该为一个对象,这样可以包含多个字段并且记录mutation会更易读。
mutations: {
increment (state, n) {
state.count += n
}
}
$state.commit('incerment',66)
传递一个对象作为参数:
mutations:{
increment(state,obj){
state.count=obj.num
}
}
$state.commit('increment',{
num:10
})
--对象风格的mutation提交方式:
直接使用包含type属性的对象方式来提交,type值为mutations内定义的回调函数名:
$store.commit({
type:'incerment',
num:66
})
--Mutation必须为同步函数,不可以是回调函数
在使用mutation时有一条重要的原则:
mutation必须为同步函数,不可以是回调函数。因为:
首先看一个简单的例子:
mutations: {
someMutation (state) {
api.callAsyncMethod(() => {
state.count++
})
}
}
每一条mutation被记录,都需要捕捉到前一状态和后一状态的快照。然而在上面的例子中mutation中的异步函数中的回调是不可能完成的,因为当mutation触发的时候,回调函数还没有被调用,vue不知道什么时候回调函数实际上被调用。
注:实际上任何在回调函数中进行的状态的改变都是不可追踪的。
--在组件中提交mutation:
方式一:
上面已经说过了这种方式:在组件中直接使用this.$store.commit('xxx')提交mutation。
方式二:
如果我们不想在template中写过多的行为(js),那么我们可以在methods中定义一个方法在方法中提交mutation:
methods:{
submit(){
this.$store.commit('xxx')
}
}
这样我们只需要在template中调用定义好的method即可,更加易读。这种方式实际上只是将template内的js换到了methods内,还是比较麻烦。
方式三:
我们可以使用mapMutations辅助函数将组件中的methods映射为store.commit调用。
注:mapMutations需要先import:
import { mapMutations } from 'vuex'
export default{
methods:{
...mapMutations({
add:'increment' //将this.add()映射为this.$store.commit('increment')
})
...mapMutations([
'increment' //将this.increment()映射为this.$store.commit('increment')
])
}
}
--通过mapMutations方式怎么传参呢?
参数并非是在mapMutations内部传递,而是在调用的地方传递参数,mapMutations只是进行映射而已。
<input type="button" value="+" @click="add(10)" />
4:Action:
Action与Mutation很相似,都是用来修改state内的状态的。
在上面Mutation内我们提到了Mutation的一个很重要的原则:Mutation必须为同步操作。
Action提交的是mutation,与Mutation不同的是:Action可以包含任意异部操作。
首先注册一个action:
const actions={
incerment(context){
context.commit('increment')
}
}
Action函数接受一个与store实例具有相同属性和方法的context对象。
因此可以调用context.commit提交一个mutation,或者通过context.state和context.getter来获取state和getters。
同样的在局部组建中import {mapActions} from 'vuex'
然后在methods内通过mapActions映射:
methods:{
...mapActions(['incerment'])
}
在template内通过事件触发:例如:@click="incerment"即可。
如果仅仅是这样那么action与mutation功能上没有任何区别,反而比mutation更加麻烦。action的作用在于执行异步操作:
const actions={
incermentAsync(context){
setTimeout(()=>{
context.commit('increment')
},5000)
}
}
5:Getter:
Getter相当于vue中的compute的计算属性,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生改变才会被重新计算。
Getter可以用于监听state中的值的变化,反悔计算后的结果。
--通过属性访问:
Getter会暴露为store.getters对象,可以以属性的形式访问这些值:
store.getters.name
--通过方法访问:
通过让getter返回一个函数来实现给getter传参。这在对store里的数组进行查询时非常有用。
getters:{
getArrId(store,id){
return (id)=>{
return state.arrdata[2]
}
}
}
注意:getter在通过方法访问时每次都会去进行调用,而不会缓存结果。
--mapGetter辅助函数:
mapGetter辅助函数仅仅是将store中的getter映射到局部的计算属性。
computeds:{
...mapGetter(['getarrdata'])
}
如果想将getter属性取另外一个name,使用对象形式:
computeds:{
...mapGetter({
getdata:'getarrdata'
})
}
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 的状态