官网:https://vuex.vuejs.org/zh-cn/
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。我把它理解为在data中的属性需要共享给其他vue组件使用的部分,就叫做状态。简单的说就是data中需要共用的属性。
Vue 的这些核心概念:
- State
- Getter
- Mutation
- Action
- Module
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); export const store = new Vuex.Store({ // 存储(状态)数据 state: { products: [ {name:'纯种马',price:200}, {name:'蒙古马',price:140}, {name:'夸特马',price:20}, {name:'阿拉伯马',price:10} ] }, // 获得state数据作为参数,定义公共方法 getters: { saleProducts: (state)=>{ var saleProducts = state.products.map(product => { return { name: "**" + product.name + "**", price: product.price/2 } }); return saleProducts; } }, // 触发事件改变数据 // 非常类似于事件,每个mutations都有一个事件类型(type)和一个回调函数(handler) // 回调函数的第一个参数为state,第二个参数为payload mutations: { reducePrice: (state,payload) => { state.products.forEach(product =>{ product.price -= payload; }); } }, // 类似mutations // 可以包含任意异步操作 // 接受与store一样的context对象,这样就可以调用context.commit提交一个mutation actions: { reducePrice: (context,payload) => { setTimeout(function(){ context.commit('reducePrice',payload); },2000); } }
一、引入
1、安装
npm install vuex --save
2、新建一个store文件夹,并在文件夹下新建store.js文件,文件中引入我们的vue和vuex。
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex);
3、在main.js引入store并注册
import {store} from './store/store.js'
new Vue({ store: store, el: '#app', router, template: '<App/>', components: { App } })
二、一个简单的Store
每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } } })
由于 store 中的状态是响应式的,在组件中调用 store 中的状态简单到仅需要在计算属性中返回即可。触发变化也仅仅是在组件的 methods 中提交 mutation。
通过 store.state
来获取状态对象,以及通过 store.commit
方法触发状态变更。
<button @click="$store.commit('add')">加</button> <p>{{$store.state.count}}</p>
三、state访问状态对象
1、通过computed的计算属性直接赋值
computed属性可以在输出前,对data中的值进行改变。
computed:{ count(){ return this.$store.state.count; } }
注意,这里要使用this,不然找不到$store。
2、通过mapState的对象来赋值
首先要用import引入mapState
import {mapState} from 'vuex';
然后还在computed计算属性里写如下代码:
computed:mapState({ count:state=>state.count })
3、通过mapState的数组来赋值
computed:mapState(['count'])
使用方便简单,实际项目经常用
4、mapState与局部计算属性混合使用,使用对象展开运算符
computed: { ...mapState(['count']) }
四、Mutations修改状态
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。
Mutations必须是同步的。
1、$store.commit()
<button @click="$store.commit('add')">+</button> <button @click="$store.commit('reduce')">-</button>
2、提交载荷(Payload) --传值
可以向 store.commit
传入额外的参数,即 mutation 的 载荷(payload)
const mutations={ add(state,payload){ state.count+=payload; }, reduce(state){ state.count--; } }
<p> <button @click="$store.commit('add',10)">+</button> <button @click="$store.commit('reduce')">-</button> </p>
3、模板获取Mutations方法
<script> import { mapState, mapMutations } from "vuex"; export default { computed: { ...mapState(['count']) }, methods: { ...mapMutations([ 'add', 'reduce' ]) } }; </script>
<button @click="add(5)">加</button> <button @click="reduce(20)">减</button>
4、使用常量替代 Mutation 事件类型
使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式。这样可以使 linter 之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然:
// mutation-types.js export const SOME_MUTATION = 'SOME_MUTATION' // store.js import Vuex from 'vuex' import { SOME_MUTATION } from './mutation-types' const store = new Vuex.Store({ state: { ... }, mutations: { // 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名 [SOME_MUTATION] (state) { // mutate state } } })
五、getters计算过滤操作
getters字面是获得的意思,可以把他看作在获取数据之前进行的一种再编辑,相当于对数据的一个过滤和加工。可以认为是 store 的计算属性。
const store = new Vuex.Store({ state: { todos: [ { id: 1, text: '...', done: true }, { id: 2, text: '...', done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) } } })
在组件中使用它:
computed: { doneTodosCount () { return this.$store.getters.doneTodosCount } }
mapGetters
辅助函数:
import { mapGetters } from 'vuex' export default { // ... computed: { // 使用对象展开运算符将 getter 混入 computed 对象中 ...mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ]) } }
六、actions异步修改状态
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } })
实践中,我们会经常用到 ES2015 的 参数解构 来简化代码:
actions: { increment ({ commit }) { commit('increment') } }
在组件中分发 Action
在组件中使用 this.$store.dispatch('xxx')
分发 action,或者使用 mapActions
辅助函数将组件的 methods 映射为 store.dispatch
调用。
import { mapActions } from 'vuex' export default { // ... methods: { ...mapActions([ 'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')` // `mapActions` 也支持载荷: 'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)` ]), ...mapActions({ add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')` }) } }
七、module模块组
随着项目的复杂性增加,我们共享的状态越来越多,这时候我们就需要把我们状态的各种操作进行一个分组,分组后再进行按组编写。
1、声明模块组
const moduleA={
state,mutations,getters,actions
}
export default new Vuex.Store({ modules:{a:moduleA} })
2、在模板中使用
插值的方式引入
<h3>{{$store.state.a.count}}</h3>
在计算属性中引入
computed:{ count(){ return this.$store.state.a.count; } },