【1】vuex 是什么
github 站点: https://github.com/vuejs/vuex,在线文档: https://vuex.vuejs.org/zh-cn/
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。每一个 Vuex 应用的核心就是 store(仓库)。“store”
基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。
Vuex 和单纯的全局对象有以下两点不同:
-
Vuex 的状态存储是响应式的。
当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。 -
你不能直接改变 store 中的状态。
改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
简单来说: 对vue 应用中多个组件的共享状态进行集中式的管理(读/写)
VueX是适用于在Vue项目开发时使用的状态管理工具。
通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
这就是 Vuex 背后的基本思想,借鉴了 Flux (opens new window)、Redux (opens new window)和 The Elm Architecture (opens new window)。与其他模式不同的是,Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。
状态管理模式&&状态自管理应用
如下一个简单计数器:
new Vue({
// state
data () {
return {
count: 0
}
},
// view
template: `
<div>{{ count }}</div>
`,
// actions
methods: {
increment () {
this.count++
}
}
})
这个状态自管理应用包含以下几个部分:
-
state: 驱动应用的数据源
-
view: 以声明方式将state 映射到视图
-
actions: 响应在view 上的用户输入导致的状态变化(包含n 个更新状态的方法)
以下是一个表示“单向数据流”理念的简单示意:
多组件共享状态的问题
多个视图依赖于同一状态,来自不同视图的行为需要变更同一状态。
以前的解决办法:
- 将数据以及操作数据的行为都定义在父组件
- 将数据以及操作数据的行为传递给需要的各个子组件(有可能需要多级传递)
vuex 就是用来解决这个问题的,vuex 是一个专门为vue.js应用程序开发的状态管理模式。
【2】VUEX核心概念和API
vuex中,有默认的五种基本的对象:state、getters、mutations、actions、modules。
state
存储状态(变量),它应该是唯一的。
/*
状态对象模块
*/
import storageUtils from '../utils/storageUtils'
export default {
todos: storageUtils.readTodos()
}
getters
对数据获取之前的再次编译,可以理解为state的计算属性。我们在组件中使用 $sotre.getters.fun()
。
- 包含多个计算属性(get)的对象
- 谁来读取: 组件中:
$store.getters.xxx
/*
包含n个基于state的getter计算属性方法的对象模块
*/
export default {
// 总数量
totalSize (state) {
return state.todos.length
}
}
mutations
修改状态,并且是同步的,在组件中使用$store.commit('',params)
。这个和我们组件中的自定义事件类似。
- 包含多个直接更新state 的方法(回调函数)的对象
- 谁来触发:
action 中的commit('mutation 名称')
- 只能包含同步的代码, 不能写异步代码
const mutations = {
yyy (state, {data1}) {
// 更新state 的某个属性
}
}
简单来说mutations是操作state数据的方法的集合,比如对该数据的修改、增加、删除等等。
actions
异步操作,在组件中使用是$store.dispath('')
。
- 包含多个事件回调函数的对象
- 通过执行
commit()来触发mutation 的调用, 间接更新state
- 谁来触发: 组件中
$store.dispatch('action 名称', data1) // 'zzz'
- 可以包含异步代码(定时器, ajax)
const actions = {
zzz ({commit, state}, data1) {
commit('yyy', {data1})
}
}
modules
store的子模块,为了开发大型项目,方便状态管理而使用的。
其包含多个module, 一个module 是一个store 的配置对象并与一个组件(包含有共享数据)对应。
使用流程如下图
组件分发(dispatch)动作到Actions,Actions提交行为到Mutations,Mutations对State进行改变然后映射到组件上。
【3】VUEX简单实例计数器
① 安装vuex
npm方式
npm install --save vuex
Yarn
yarn add vuex
② main.js引入
/*
入口js
*/
import Vue from 'vue'
import Counter from './Counter.vue'
import store from './store'
new Vue({
el: '#app',
components: {
Counter
},
template: '<Counter/>',
store // 注册上vuex的store: 所有组件对象都多一个属性$store
})
③ Counter组件
<template>
<div>
<p>click {{count}} times, count is {{evenOrOdd}}</p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementIfOdd">increment if odd</button>
<button @click="incrementAsync">increment async</button>
</div>
</template>
<script>
export default {
mounted () {
console.log(this.$store)
},
computed: {
count () {
return this.$store.state.count
},
evenOrOdd () {
return this.$store.getters.evenOrOdd
}
},
methods: {
increment () {
this.$store.dispatch('increment')
},
decrement () {
this.$store.dispatch('decrement')
},
incrementIfOdd () {
this.$store.dispatch('incrementIfOdd')
},
incrementAsync () {
this.$store.dispatch('incrementAsync')
}
}
}
</script>
<style>
</style>
computed和methods可以优化为如下:
import {mapState, mapGetters, mapActions} from 'vuex'
computed: {
...mapState(['count']),
...mapGetters(['evenOrOdd'])
},
methods: {
...mapActions(['increment', 'decrement', 'incrementIfOdd', 'incrementAsync'])
}
④ store.js
/*
vuex最核心的管理对象store
*/
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
/*
相当于data对象的状态对象
*/
const state = {
count: 0 // 指定初始化数据
}
/*
包含了n个直接更新状态的方法的对象
*/
const mutations = {
INCREMENT (state) {
state.count++
},
DECREMENT (state) {
state.count--
}
}
/*
包含了n个间接更新状态的方法的对象 actions-->mutations
*/
const actions = {
increment ({commit}) {
// 提交一个mutation请求
commit('INCREMENT')
},
decrement ({commit}) {
// 提交一个mutation请求
commit('DECREMENT')
},
incrementIfOdd ({commit, state}) {
if(state.count%2===1) {
// 提交一个mutation请求
commit('INCREMENT')
}
},
incrementAsync ({commit}) {
setTimeout(() => {
// 提交一个mutation请求
commit('INCREMENT')
}, 1000)
},
}
/*
包含多个getter计算属性的对象
*/
const getters = {
evenOrOdd (state) { // 当读取属性值时自动调用并返回属性值
return state.count%2===0 ? '偶数' : '奇数'
}
}
**向外暴露store 对象**
export default new Vuex.Store({
state,
mutations,
actions,
getters
})