组件是Vue最强大的功能之一,而组件实例的做用域是相互独立的,意味着不一样组件之间的数据是没法相互使用。组件间如何传递数据就显得相当重要,这篇文章主要是介绍Vuex。尽可能以通俗易懂的实例讲述这其中的差异,但愿对小伙伴有些许帮助。html
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的全部组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。vue
一个简单的 Vue 计数应用开始:面试
new Vue({ // state data () { return { count: 0 } }, // view template: ` <div>{{ count }}</div> `, // actions methods: { increment () { this.count++ } } })
这个状态自管理应用包含如下几个部分:vuex
state,驱动应用的数据源;
view,以声明方式将 state 映射到视图;
actions,响应在 view 上的用户输入致使的状态变化。segmentfault
state的数据会在 view上显示出来,用户会根据 view 上的内容进行操做,从而触发 actions,接着再去影响 state(vue 是单向数据流的方式驱动的)。缓存
当咱们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏。下面的图,是把组件的共享状态抽取出来,以一个全局单例模式管理。app
1. state
state:页面状态管理容器对象。集中存储Vue components中data对象的零散数据,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取。异步
<div> {{ $store.state.count }} </div> console.log(this.$store.state.count)
2. getters
getters:Vuex 容许咱们在 store 中定义“getter”(能够认为是 store 的计算属性)。就像计算属性同样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被从新计算。(getters从表面是得到的意思,能够把他看做在获取数据以前进行的一种再编辑,至关于对数据的一个过滤和加工。getters就像计算属性同样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被从新计算。)函数
定义getter:this
getters: { done(state) { return state.count + 1; }, }
3. mutations
mutations:更改 Vuex 的 store 中的状态的惟一方法是提交 mutation。Vuex 中的 mutation 很是相似于事件:每一个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是咱们实际进行状态更改的地方,而且它会接受 state 做为第一个参数:
const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { // 变动状态 state.count++ } } })
组件经过commit提交mutations的方式来请求改变state
this.$store.commit('increment')
提交载荷(Payload)
mutations方法中是能够传参的,具体用法以下:
mutations: { // 提交载荷 Payload add(state, n) { state.count += n } }, this.$store.commit('add', 10)
4.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') } } })
不一样于mutations使用commit方法,actions使用dispatch方法。
this.$store.dispatch('incrementAsync')
context
context是与 store 实例具备相同方法和属性的对象。能够经过context.state和context.getters来获取 state 和 getters。
以载荷形式分发
incrementAsyncWithValue (context, value) { setTimeout(() => { context.commit('add', value) }, 1000) } this.$store.dispatch('incrementAsyncWithValue', 5)
5.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 } } }
在src目录下建立一个store文件夹。
store/store.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { count: 0, show: '' }, getters: { counts: (state) => { return state.count } }, mutations: { increment: (state) => { state.count++ }, decrement: (state) => { state.count-- }, changVal: (state, v) => { state.show = v } } }) export default store
state就是咱们的须要的状态,状态的改变只能经过提交mutations,例如:
increase() { this.$store.commit('increment') }
带有载荷的提交方式:
changObj () { this.$store.commit('changVal', this.obj) }
载荷也能够是一个对象,这样能够提交多个参数。
changObj () { this.$store.commit('changVal', { key:'' }) }
在main.js中引入store.js
import store from './store/store' export default new Vue({ el: '#app', router, store, components: { App }, template: '<App/>' })
在组件中使用
在组建能够经过$store.state.count得到状态
更改状态只能以提交mutation的方式。
<div class="store"> <p> {{$store.state.count}} </p> <button @click="increase"><strong>+</strong></button> <button @click="decrease"><strong>-</strong></button> <hr> <h3>{{$store.state.show}}</h3> <input placeholder="请输入内容" v-model="obj" @change="changObj" clearable> </input> </div> </template> <script> export default { data () { return { obj: '' } }, methods: { increase() { this.$store.commit('increment') }, decrease() { this.$store.commit('decrement') }, changObj () { this.$store.commit('changVal', this.obj) } } } </script>
不少时候 , $store.state.dialog.show 、$store.dispatch('switch_dialog') 这种写法又长又臭 , 很不方便 , 咱们没使用 vuex 的时候 , 获取一个状态只须要 this.show , 执行一个方法只须要 this.switch_dialog 就好了 , 使用 vuex 使写法变复杂了 ?使用 mapState、mapGetters、mapActions 就不会这么复杂了。
以 mapState 为例 :
<template> <el-dialog :visible.sync="show"></el-dialog> </template> <script> import {mapState} from 'vuex'; export default { computed:{ //这里的三点叫作 : 扩展运算符 ...mapState({ show:state=>state.dialog.show }), } } </script>
至关于 :
<template> <el-dialog :visible.sync="show"></el-dialog> </template> <script> import {mapState} from 'vuex'; export default { computed:{ show(){ return this.$store.state.dialog.show; } } } </script>
mapGetters、mapActions 和 mapState 相似 , mapGetters 通常也写在 computed 中 , mapActions 通常写在 methods 中。
Vuex官方文档