Vuex
Vuex是一个专门为Vue.js应用程序开发的状态管理模式。
- 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
- Vuex也集成到Vue的官方调试工具devtools extension,提供了诸如零配置的time-travel调试、状态快照导入导出等高级调试功能。
使用
安装Vuex:
npm install --save vuex
在src下新建store文件夹,在其中新建index.js作为Vuex的配置文件:
import Vue from 'vue'
import Vuex from 'vuex'
//安装插件
Vue.use(Vuex)
//创建对象
const store = new Vuex.Store({
})
//导出
export default store
在main.js中引入注册:
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store';
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
仓库store包含了应用的数据(状态)和操作过程。Vuex里的数据都是响应式的,任何组件使用同一个store的数据时,只要store的数据变化,对应的组件也会立即更新。
数据保存在Vuex选项的state 字段内,比如要实现一个计数器,定义一个数据count,初始值为0:
const store = new Vuex.Store({
state: {
counter: 1000
}
})
在App.vue中使用:
<template>
<div id="app">
<h2>App</h2>
<h2>{{$store.state.counter}}</h2>
</div>
</template>
现在访问首页,计数0已经可以显示出来了。
在组件内,来自store的数据只能读取,不能手动改变,改变store中数据的唯一途径就是显示的提交mutations,用来加1和减1。
const store = new Vuex.Store({
state: {
counter: 1000
},
mutations: {
//
//方法,默认参数为state
increment(state) {
state.counter++
},
decrement(state) {
state.counter--
}
}
})
在组件内,通过this.$store.commit方法来执行mutations。在App.vue中添加两个按钮用于加和键:
<template>
<div id="app">
<h2>App</h2>
<h2>{{$store.state.counter}}</h2>
<button @click="handleIncrement">+1</button>
<button @click="handleDecrease">-1</button>
</div>
</template>
<script>
import HelloVuex from './components/HelloVuex'
export default {
name: 'App',
components: {
},
data() {
},
methods: {
handleIncrement(){
this.$store.commit('increment')
},
handleDecrease(){
this.$store.commit('decrement')
}
}
}
</script>
<style>
</style>
mutations还可以接收第二个参数,可以是数字、字符串或对象等类型。比如每次增加的不是1,而是指定的数量,可以这样改写:
mutations: {
//方法,默认参数为state
increment(state, n) {
state.counter += n
},
decrement(state, n) {
state.counter += n
}
}
methods: {
handleIncrement(){
this.$store.commit('increment', 10)
},
handleDecrease(){
this.$store.commit('decrement', 10)
}
}
提交mutation的另一种方式是直接使用包含type属性的对象,例如:
increment(state, n) {
state.counter += n.count
}
handleIncrement(){
this.$store.commit({
type: 'increment',
count: 10
})
}
Vuex还有其它三个选项可以使用:getters、actions、modules
getter:(类似组件的计算属性computed)
假如Vuex定义了某个数据List,它是一个数组:
state: {
counter: 1000,
list: [1, 5, 8, 10, 30, 50]
}
如果只想要得到小于10的的数据,可以在getters中定义过滤方法:
getters: {
//类似组件的计算属性
filteredList: state => {
return state.list.filter(item => item < 10)
}
}
在App.vue中使用:
<h2>{{$store.getters.filteredList}}</h2>
getters也可以依赖其它的getter,把getter作为第二个参数,例如再写一个getter,计算出list过滤后的结果的数量:
filteredList: state => {
return state.list.filter(item => item < 10)
},
listCount: (state, getters) => {
return getters.filteredList.length;
}
<h2>{{$store.getters.listCount}}</h2>
<h2>{{$store.getters.filteredList}}</h2>
actions:
mutation中不应该异步操作数据,所以有了actions选项。
action在组件内通过$store.dispatch触发,例如使用action来减1,使用Promise在1秒后提交mutation:
mutations: {
//
//方法,默认参数为state
increment(state, n) {
state.counter += n.count
},
decrement(state, n) {
state.counter -= n
}
},
actions: {
//在这里定义异步操作
asyncDecrement(context){
return new Promise((resolve, reject) => {
setTimeout(() => {
context.commit('decrement', 10)
resolve()
}, 1000)
})
}
}
App.vue:
<template>
<div id="app">
<h2>App</h2>
<h2>{{$store.state.counter}}</h2>
<button @click="handleIncrement">+1</button>
<button @click="handleActionDecrease">-1</button>
<h2>{{$store.getters.listCount}}</h2>
<h2>{{$store.getters.filteredList}}</h2>
</div>
</template>
<script>
export default {
name: 'App',
components: {
},
methods: {
handleIncrement(){
this.$store.commit({
type: 'increment',
count: 10
})
},
handleActionDecrease(){
this.$store.dispatch('asyncDecrement').then(() => {
console.log(this.$store.state.counter);//990
})
}
}
}
</script>
<style>
</style>
modules:
它用来将store分割到不同模块。当项目足够大时,store里的state、getters、mutations、actions会非常多,都放在一个index.js中就不是很友好,使用modules可以把他们写到不同的文件中。
每个module拥有自己的state、getters、mutations、actions,而且可以多层嵌套。
例如:
const moduleA = {
state: {...},
mutations: {...},
actions: {...},
getters: {...}
}
const moduleB = {
state: {...},
mutations: {...},
actions: {...},
getters: {...}
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a//moduleA的状态
store.state.b//moduleB的状态
另外,module的mutation和getter接受的第一个参数state是当前模块的状态。在actions和getters中,还可以接收一个参数rootState,来访问根节点的状态。比如getters中rootState将作为第三个参数:
const moduleA = {
state: {
count: 0
},
getters: {
sumCount (state, getters, rootState) {
return state.count + rootState.count;
}
}
}