vue vuex的state,getter,mustation,action,module

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

Vuex核心属性:

vuex中给出了几个核心名词,state,getter,mutation,action,module。
我们画图说明。

属性名 描述
state 仓库,里面存放数据
getter 搬运工小组,有无数个搬运工,只负责从厂房往外搬东西
mutation 操作工小组,有无数个操作工,负责更新货物,只能同步进行
action 操作工小组,有无数个操作工,负责更新货物,可以异步进行
module 工厂里的厂区,vuex里面可以有无数个厂区

vuex的使用:

// 下载vuex包 npm install --save vuex
然后我们在src目录下,创建一个store目录,在该目录下创建一个index.js文件。

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

// 数据仓库
const state = {
  // 定义一个公共属性,并初始化赋值
  name: '厂长'
}

// 数据的搬运工,我可以在其中定义搬运规则
const getters = {
  getName: function (state) {
    // 在这里定义搬运规则,然后返回
    return state.name + '是我表哥'
  }
}

// mutations操作工,专门用于修改state里的属性的方法集合,只能同步
const mutations = {
  setName (state, payload) {
    state.name = payload
  }
}

// actions操作工,用于修改state里的属性的方法集合,可以异步
const actions = {
  setName (context, payload) {
    // 这里进行异步操作,最后还是调用了mutations中的方法
    context.commit('setName', payload)
  }
}

// 导出
export default new Vuex.Store({
  state: state,
  mutations: mutations,
  getters: getters,
  actions: actions
  
  // 如果参数名相同,可以简写
  state,
  getters,
  mutations,
  actions
})

注意,注意,注意,这里参数,vuex已经规定好了,只能是state,getters,mutations,actions。

最后,别忘了在main.js入口文件中导入该文件。

import Vue from 'vue'
import App from './App'
import router from './router'

// 在这里导入
import store from './store'
import Vuex from 'vuex'

Vue.use(Vuex)

new Vue({
  el: '#app',
  router,
  // 添加到vue实例
  store,
  components: {
    App
  },
  template: '<App/>'
})

简单的说明了一下vuex,假设厂长是我表哥,我现在可以指挥这个工厂了。

state应用:

上面说过了,state里存放的是数据,要想获取数据,有两种办法。

第一种:厂长亲自来取数据,缺点是不能定义规则。
第二种:厂长叫getter搬运工去取,getter搬运工有定义规则的能力。

既然厂长是我表哥,那么就由我代劳了。

在任何组件中,我们都可以使用以下方式,获取state中的数据。

this.$store.state.name

// 一般,我们会放在computed里。
computed: {
  showName () {
    return this.$store.state.name
  }
}

以上内容可以发现,厂长可以直接来取数据,但缺点是无法过滤数据。

getter应用:

getter专门用来取数据的,并且我可以在里面定义各种各样的规则。

举例说明。

const state = {
  // 定义了一个数组,里面包含员工,和他对应的工资
  data: [{
    name: '牛二',
    salary: 3000
  }, {
    name: '张三',
    salary: 3200
  }, {
    name: '李四',
    salary: 3600
  }, {
    name: '王麻子',
    salary: 3800
  }]
}

假设,厂长现在要给工资3500以下的人涨工资,那么我们就可以通过getter知道,有那些人的工资在3500以下。

const getters = {
  getName: function (state) {
    var people = []
    for (var temp of state.count) {
      if (temp.salary < 3500) {
        people.push(temp)
      }
    }
    return people
  }
}

export default new Vuex.Store({
  state,
  getters
})

在任何组件中,我们都可以使用以下方式,通过getter获取state中的数据。

this.$store.getters.getName

当然,也可以放在computed里封印起来。

computed: {
  showName () {
    return this.$store.getters.getName
  }
}

这里要注意的是官方给出的说明,如下。
Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

mutation应用:

mutation专门用来更新数据的。
最重要的是:mutation是同步的,同步的,同步的。

官方给出的说明如下。
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。
举例说明

const state = {
  name: '厂长'
}

const mutations = {
  // 在这里进行更改
  setName (state) {
    state.name += '是我表哥'
  }
}

export default new Vuex.Store({
  state,
  mutations
})

既然mutation被当做事件,那么就不能称之为调用了,在vuex中,通过以下方式,触发mutation。

store.commit('setName')
那么,也就是说,在任何组件里,都可以通过如下方式,使用mutation,一般将mutation封印在methods中。

this.$store.commit('xxx')

以上例子中,name的变更方式已经被固定死了,我希望按照我制定的方式变更。
vuex中有如下说明。
你可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload)
举例说明

const state = {
  name: '厂长'
}

const mutations = {
  // 接收一个str参数,即mutation的载荷
  setName (state, str) {
    state.name += str
  }
}

export default new Vuex.Store({
  state,
  mutations
})

触发方式不变,也就是多了个参数。

store.commit('setName', '是我表哥')

action应用:

action和mutation同样是操作工,但是action还是要牛一些的。
action牛的地方在于,有些活儿他不干,他让mutation去干。
最重要的是,action可以异步,可以异步,可以异步。

官方有如下说明。

Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。```

比如,我现在让action去干活,他觉得活儿太简单了,就让action去干,结果就是他睡一觉起来,活儿干完了。

举例说明。

const actions = {
setName (context, name) {
// action自己去睡了一觉,让mutation去干活
setTimeout(() => {
context.commit('setName', name)
}, 5000)
}
}

action的调用,称之为分发,在vuex中,通过以下方式,分发action。

`store.dispatch('setName', name)
`
在任何组件里,都可以通过如下方式,使用action,一般将action封印在methods中。

`this.$store.dispatch('xxx')
`
这里要注意的是:
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,我们可以通过这个 context 对象获取当前 store 实例的 state 和 getters,但是这个 context 对象,不是 store 实例本身,不是,不是,不是。
上图说明
##### context 对象
![](https://img2018.cnblogs.com/blog/1545354/201903/1545354-20190313164119686-1188430760.png)

##### store 实例

![](https://img2018.cnblogs.com/blog/1545354/201903/1545354-20190313164206101-110479817.png)

只是有点像,但是二者不一样。

#### module应用:
module的作用就是将state,getter,mutation,action拆分,这样就避免了所有代码混在一起的情况。

举例说明。

const moduleA = {
state: {
name: '模块A'
},
mutations: {},
actions: {},
getters: {}
}

const moduleB = {
state: {
name: '模块B'
},
mutations: {},
actions: {},
getters: {}
}

export default new Vuex.Store({
state: {
name: '根节点'
},
mutations: {},
actions: {},
getters: {},
modules: {
a: moduleA,
b: moduleB
}
})

这里要注意的是,模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象。
也就是说,模块内部的mutation和getter,用的是自己的仓库。
而action接收的还是一个和store实例相似的对象。
举例说明

const moduleA = {
namespaced: true,
state: {
name: '模块A'
},
mutations: {
myMutation: function (
// 如果在模块中定义则为模块的局部状态
state,
// 载荷,可选
payload) {

}

},
actions: {
myAction: function (
// context对象
{
state,
rootState,
commit,
dispatch,
getters,
rootGetters
},
// 载荷,可选
payload) {

}

},
getters: {
myGetter: function (
// 如果在模块中定义则为模块的局部状态
state,
// 等同于 store.getters
getters,
// 等同于 store.state
rootState,
// 所有 getters
rootGetters) {
return state.data
}
}
}

即使是分了模块,state,getter,mustation,action的使用方法还是一样。

// 使用state
this.\(store.state.name // 使用getter this.\)store.getters.myGetter
// 使用mutation
this.\(store.commit('myMutation', '哈哈哈') // 使用action this.\)store.dispatch('myAction', '哈哈哈')


那么问题来了,如果模块A和模块B中的属性和方法重名,怎么办?

举例说明。

const moduleA = {
state: {
name: '模块A'
},
mutations: {
aaa: function (state) {}
},
actions: {
bbb: function (context) {}
},
getters: {
ccc: function (state) {}
}
}

const moduleB = {
state: {
name: '模块B'
},
mutations: {
aaa: function (state) {}
},
actions: {
bbb: function (context) {}
},
getters: {
ccc: function (state) {}
}
}

使用命名空间
举例说明。

const moduleA = {
namespaced: true,
state: {
name: '模块A'
}
}

const moduleB = {
namespaced: true,
state: {
name: '模块B'
}
}

export default new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})


在上述例子中,我加了一个属性`namespaced: true`,表示使用命名空间,那么在使用state,getter,mustation,action时,就得加上命名空间。

// 使用state
this.\(store.state.a.name // 使用getter this.\)store.getters['a/myGetter']
// 使用mutation
this.\(store.commit('a/myMutation', '哈哈哈') // 使用action this.\)store.dispatch('a/myAction', '哈哈哈')


还有就是,module还可以嵌套,不过基本上都是大同小异
posted @ 2019-03-13 16:45  Heson  阅读(985)  评论(0编辑  收藏  举报
Live2D