爱生活,爱编程,学习使我快乐
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
每一个 Vuex 应用的核心就是 store(仓库)。看起来很像一个全局对象,但又不是全局对象。
Vuex 和单纯的全局对象有以下两点不同:
你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
使用 Vuex 并不意味着你需要将所有的状态放入 Vuex。虽然将所有的状态放到 Vuex 会使状态变化更显式和易调试,但也会使代码变得冗长和不直观。如果有些状态严格属于单个组件,最好还是作为组件的局部状态。你应该根据你的应用开发需要进行权衡和确定。
this.$store.commit
提交一个mutations,让mutations去修改state的值。this.$store.dispatch
派发一个actions。在actions中处理异步操作(如:请求接口获取数据)然后在actions中再提交一个mutations,再让mutations去修改state的值。
在mutations中去修改state的值。
state的值变化,再影响到视图的渲染。
下图说明了vuex的工作流程
接下来我们以“计数器”实例来讲述
store文件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
getters: {
// getter可以认为是store的计算属性
// getter正常接受两个参数,分别表示 state, getters(在使用module时,还会有根store的state和getters)
doubleCount: (state, getters) => {
return state.count * 2
}
},
mutations: {
increment (state) {
state.count++
},
addForNum (state, payload) {
state.count += Number(payload.num)
},
asyncAdd (state) {
state.count += 10
}
},
actions: {
// 异步操作需要放在actions中执行,然后使用commit交给对应的mutations修改state的值
asyncAddAction (context) {
setTimeout (function () {
context.commit('asyncAdd')
}, 500)
}
}
})
export default store
组件文件
模板部分
<template>
<div>
<h2>这是计数器页面</h2>
<div>
<div>计数:{{count}}</div>
<div>双倍计数:{{doubleCount}}</div>
<br/>
<button @click="increment">+1</button>
<div>
增加值 <input type="text" v-model="num" />
<button @click="addForNum">=</button>
</div>
<div>
<button @click="asyncAdd">异步加10</button>
</div>
</div>
</div>
</template>
javascript部分
export default {
name: 'index',
data () {
return {
num: 0
}
},
computed: {
count () {
return this.store.state.count
},
doubleCount () {
return this.store.getters.doubleCount
}
},
methods: {
// 自增1
increment () {
this.store.commit('increment')
},
// 加指定的值
addForNum () {
this.store.commit('addForNum', {num: this.num})
},
// 异步加1
asyncAdd () {
this.$store.dispatch('asyncAddAction')
}
}
}
我们可以使用map辅助函数使代码更精简
store文件中的内容不需要变动,只要在组件中使用map辅助函数来替代全局的this.$sotre
下的属性和方法即可。
组件文件修改如下:
模板部分
<template>
<div>
<h2>这是计数器页面</h2>
<div>
<div>计数:{{count}} - {{countAlias}}</div>
<div>双倍计数:{{doubleCount}} - {{doubleCountAlias}}</div>
<br/>
<button @click="increment">+1</button>
<div>
增加值 <input type="text" v-model="num" />
<button @click="incrementBy(num)">=</button>
</div>
<div>
<button @click="asyncAdd">异步加10</button>
</div>
</div>
</div>
</template>
javascript部分
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
export default {
name: 'index',
data () {
return {
num: 0,
localCount: 10
}
},
computed: {
/*
* ------------------------------------------------------------
* mapState
*/
// 【传统形式】
// count () {
// return this.store.state.count
// },
// 【对象形式】
...mapState({
// 箭头函数可使代码更简练
count: state => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
// 使用这种方式可以更简洁地为state生成的计算属性定义一个别名
countAlias: 'count',
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
}),
// 【数组形式】
// 当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组。
...mapState([
// 映射 this.count 为 store.state.count
'count'
]),
/*
* ------------------------------------------------------------
* mapGetters
*/
// 【传统形式】
// doubleCount () {
// return this.store.getters.doubleCount
// }
// 【对象形式】
// 如果你想将一个 getter 属性另取一个名字,使用对象形式
...mapGetters({
// 把 `this.doubleCountAlias` 映射为 `this.store.getters.doubleCount`
doubleCountAlias: 'doubleCount'
}),
// 【数组形式】
...mapGetters(['doubleCount'])
},
methods: {
/*
* ------------------------------------------------------------
* mapMutations
*/
// 【传统形式】
// 自增1
// increment () {
// this.store.commit('increment')
// },
// // 加指定的值
// incrementBy (amount) {
// this.store.commit('incrementBy', amount)
// },
// 【数组形式】
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.store.commit('increment')`
// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.store.commit('incrementBy', amount)`
]),
// 【对象形式】
...mapMutations({
add: 'increment' // 将 `this.add()` 映射为 `this.store.commit('increment')`
}),
// // 异步加1
// asyncAdd () {
// this.store.dispatch('asyncAddAction')
// }
/*
* ------------------------------------------------------------
* mapActions
*/
// 【数组形式】
...mapActions([
'asyncAddAction', // 将 `this.asyncAddAction()` 映射为 `this.store.dispatch('asyncAddAction')`
]),
// 【对象形式】
...mapActions({
asyncAdd: 'asyncAddAction' // 将 `this.asyncAdd()` 映射为 `this.$store.dispatch('asyncAddAction')`
})
}
}
上面讲到了利用【this.$store】和【map辅助函数】两种方式来使用vuex,同样也可以两者混合使用。不过建议还是使用其中一种方式,使代码风格统一比较好。个人建议使用【map辅助函数】风格更好一些,因为【map辅助函数】显的代码更精简。当前还是要以自己的习惯为主,你可以自己选择自己喜欢的风格。