初步认识Vuex
1)Vuex是一个专为Vue.js应用程序开发的转态管理模式;集中存储和管理应用的全部组件状态。
2)使用场景:
处理多组件依赖于同一个数据
一个组件的行为——改变数据——影响另外一个组件的视图(共用依赖的数据)
Vuex将组件公用数据抽离,在一个公共仓库管理,使得各个组件容易获取(getter)数据,也容易设置数据(setter)。html
Vuex之store
1)Store类就是在存储数据和管理数据方法的仓库,实现方式就是将数据和方法以对象形式传入其实例中。要注意一个应用或项目中只能存在一个Store实例。vue
sate
用来存放组件之间共享的数据es6
mutations(只能处理同步函数)
改变状态(state)的惟一方式是经过提交(commit)一个mutationajax
getters
对state的数据进行筛选,过滤vuex
actions(能够包含任意异步操做,ajax、setTimeout、setInterval)npm
https://vuex.vuejs.org/zh/ins...api
1)安装数组
npm install vuex --save 或 yarn add vuex
在一个模块化的打包系统中,您必须显示地经过Vue.use()来安装Vuex:promise
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex)
当使用全局script标签引用Vuex时,不须要以上安装过程浏览器
Vuex依赖Promise(不支持promise的浏览器)
<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.js"></script> npm install es6-promise --save # npm yarn add es6-promise # Yarn import 'es6-promise/auto'
2)State
Vuex使用单一状态树,用一个对象包含了所有的应用层级状态。这也意味着,每一个应用将仅仅包含一个store实例。(因为 store 中的状态是响应式的,在组件中调用 store 中的状态简单到仅须要在计算属性(computed)中返回便可。)
在Vue组件中得到Vuex状态
最简单的方法是在计算属性中返回某个状态
// 建立一个 Counter 组件 const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { return store.state.count } } }
然而,这种模式致使组件依赖全局状态单例。在模块化的构建系统中,在每一个须要使用 state 的组件中须要频繁地导入,而且在测试组件时须要模拟状态。
Vue经过store选项,提供了一种机制将状态从根组件“注入”到每一个子组件中(须要调用Vue.use(Vuex))
const app = new Vue({ el: '#app', // 把 store 对象提供给 “store” 选项,这能够把 store 的实例注入全部的子组件 store, components: { Counter }, template: ` <div class="app"> <counter></counter> </div> ` }) const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { return this.$store.state.count } } }
mapState辅助函数
// 在单独构建的版本中辅助函数为 Vuex.mapState import { mapState } from 'vuex' export default { // ... computed: mapState({ // 箭头函数可以使代码更简练 count: state => state.count, // 传字符串参数 'count' 等同于 `state => state.count` countAlias: 'count', // 为了可以使用 `this` 获取局部状态,必须使用常规函数 countPlusLocalState (state) { return state.count + this.localCount } }) } computed: mapState([ // 映射 this.count 为 store.state.count 'count' ])
对象展开运算符(mapState函数返回的是一个对象)
computed: { localComputed () { /* ... */ }, // 使用对象展开运算符将此对象混入到外部对象中 ...mapState({ // ... }) }
3)Getter
Vuex容许咱们在store中定义“getter”(能够认为是store的计算属性)。就像是计算属性同样,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被从新计算。(通常用于派生状态)
Getter接受state作为其第一个参数:
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) } } })
Getter会暴露store.getters对象,能够以属性的形式访问这些值:
getters: { // ... doneTodosCount: (state, getters) => { return getters.doneTodos.length } } store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
注意,getter 在经过属性访问时是做为 Vue 的响应式系统的一部分缓存其中的。
你也能够经过让 getter 返回一个函数,来实现给 getter 传参。在你对 store 里的数组进行查询时很是有用。
getters: { // ... getTodoById: (state) => (id) => { return state.todos.find(todo => todo.id === id) } } store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
mapGetters辅助函数
mapGetters辅助函数仅仅是将store中的getter映射到局部计算属性:
import { mapGetters } from 'vuex' export default { // ... computed: { // 使用对象展开运算符将 getter 混入 computed 对象中 ...mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ]) } }
若是你想将一个getter属性另取一个名字,使用对象形式
mapGetters({ // 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount` doneCount: 'doneTodosCount' })
4)Mutation
更改Vuex的store中的状态的惟一方法是提交mutation。Vuex中的mutation很是相似于事件:每一个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)。这个回调函数就是咱们实际进行状态更改的地方,而且它会接受state做为第一个参数:
const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { // 变动状态 state.count++ } } })
你不能直接调用一个mutation handler。这个选项更像是事件注册:"当触发一个类型为increment的mutation时,调用此函数。"要唤醒一个mutation handler,你须要以相应的type调用store.commit方法:
store.commit('increment')
你能够向 store.commit 传入额外的参数,即 mutation 的 载荷(payload):
// ... mutations: { increment (state, n) { state.count += n } } store.commit('increment', 10)
在大多数状况下,载荷应该是一个对象,这样能够包含多个字段而且记录的mutation会更易读:
// ... mutations: { increment (state, payload) { state.count += payload.amount } } store.commit('increment', { amount: 10 })
提交mutation的另外一种方式是直接使用包含type属性的对象
store.commit({ type: 'increment', amount: 10 }) mutations: { increment (state, payload) { state.count += payload.amount } }
mutation必须是同步函数
5)Action
Action相似于mutation,不一样在于:
Action提交的是mutation,而不是直接变动状态。
Action能够包含任意异步操做
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } })
Action 函数接受一个与 store 实例具备相同方法和属性的 context 对象,所以你能够调用 context.commit 提交一个 mutation,或者经过 context.state 和 context.getters 来获取 state 和 getters。
Action经过store.dispatch方法触发:
store.dispatch('increment')
咱们能够在 action 内部执行异步操做:
actions: { incrementAsync ({ commit }) { setTimeout(() => { commit('increment') }, 1000) } } Actions 支持一样的载荷方式和对象方式进行分发: // 以载荷形式分发 store.dispatch('incrementAsync', { amount: 10 }) // 以对象形式分发 store.dispatch({ type: 'incrementAsync', amount: 10 })
store.dispatch 能够处理被触发的 action 的处理函数返回的 Promise,而且 store.dispatch 仍旧返回 Promise:
actions: { actionA ({ commit }) { return new Promise((resolve, reject) => { setTimeout(() => { commit('someMutation') resolve() }, 1000) }) } } store.dispatch('actionA').then(() => { // ... })
6)Module
因为使用单一状态树,应用的全部状态会集中到一个比较大的对象。当应用变得很是复杂时,store 对象就有可能变得至关臃肿。
为了解决以上问题,Vuex 容许咱们将 store 分割成模块(module)。每一个模块拥有本身的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行一样方式的分割:
const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) store.state.a // -> moduleA 的状态 store.state.b // -> moduleB 的状态
对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象。
const moduleA = { state: { count: 0 }, mutations: { increment (state) { // 这里的 `state` 对象是模块的局部状态 state.count++ } }, getters: { doubleCount (state) { return state.count * 2 } } }
一样,对于模块内部的 action,局部状态经过 context.state 暴露出来,根节点状态则为 context.rootState:
const moduleA = { // ... actions: { incrementIfOddOnRootSum ({ state, commit, rootState }) { if ((state.count + rootState.count) % 2 === 1) { commit('increment') } } } }
对于模块内部的 getter,根节点状态会做为第三个参数暴露出来:
const moduleA = { // ... getters: { sumWithRootCount (state, getters, rootState) { return state.count + rootState.count } } }
默认状况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块可以对同一 mutation 或 action 做出响应。
项目结构 ├── index.html ├── main.js ├── api │ └── ... # 抽取出API请求 ├── components │ ├── App.vue │ └── ... └── store ├── index.js # 咱们组装模块并导出 store 的地方 ├── actions.js # 根级别的 action ├── mutations.js # 根级别的 mutation └── modules ├── cart.js # 购物车模块 └── products.js # 产品模块