每一个Vuex应用的核心就是store。store基本上就是一个容器,它包含着你的应用中大部分的状态。vuex和单纯的全局对象有以下两点不同:1.Vuex的状态存储是响应式的。当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会相应地得到高效更新。2.你不能直接改变store中的状态。改变store中的状态的唯一途径就是显式地提交(commit)mutation。这样使得我们可以方便的跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好的了解我们的应用。//如果在模块化构建系统中,请确保在开头调用了Vue.use(Vuex)const store = new Vuex.Store({ state:{ count:0 }, mutations:{ increment(state){ state.count++ } }})现在可以通过store.state来获取状态对象,以及通过store.commit方法触发状态变更:store.commit(‘increment’)console.log(store.state.count)//1再次强调,我们通过提交mutation的方式,而非直接改变store.state.count,是因为我们想要更明确地追踪到状态的变化。这个简单的约定能够让你的意图更加明显,这样你在阅读代码的时候更容易地解读应用内部的状态改变。此外,这样也让我们有机会去实现一些能记录每次状态改变,保持状态快照的调试工具。stateVuex使用单一状态树,用一个对象就包含了全部的应用层级状态。至此它便作为一个唯一数据源而存在。这也意味着,每个应用将仅仅包含一个store实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。//创建一个Counter组件const Counter = { template:<div>{{count}}</div>
, computed:{ count(){ return store.state.count } }}每当store.state.count变化的时候,都会重新求取计算属性,并且触发更新相关联的DOM。然而,这种模式导致组件依赖全局状态单例。在模块化的构建系统中,在每个需要使用state的组件中需要频繁地导入,并且在测试组件时需要模拟状态。Vuex通过store选项,提供了一种机制将状态从根组件注入到每一个子组件(需要调用Vuex.use(Vuex));const app = new Vue({ el:’#app’, //把store对象提供给store选项,这可以把store的实例注入所有的子组件。 store, components:{Counter}, template: <div class="app"> <counter></counter> </div>
})通过在根实例中注册store选项,该store实例会注入到根组建下的所有子组件中,且子组件能通过this.$store访问到。让我们更新下Counter的实现:const Counter = { template:<div>{{count}}</div>
, computed:{ count(){ return this.$store.state.count } }}mapState辅助函数当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用mapState辅助函数帮我们生成计算属性:mapState函数返回的是一个对象。//再单独构建的版本中辅助函数为Vuex.mapStateimport {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 } }), //当映射的计算属性的名称于state的子节点名称相同时,我们也可以给mapState传一个字符串数组。 computed:mapState([ //映射this.count为store.state.count ‘count’ ]) //使用对象展开运算符与computed混合使用。 computed:{ loacalComputed(){}, //使用对象展开运算符将此对象混入到外部对象中 …mapState({ //… }) }} Getter有时候我们需要从store中的state中派生出一些状态,例如对列表进行过滤并技数:Vuex允许我们在store中定义getter(可以认为是store的计算属性)。就像计算属性一样,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。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对象,你可以以属性的形式访问这些值:store.getters.doneTodos//[{id:1,text:’…’,done:true}]getter也可以接受其它getter作为第二个参数:getters:{ //… doneTodosCount:(state,getters)=>{ return getters.doneTodos.length }}我们可以很容易地在任何组件中使用它:computed: { doneTodosCount () { return this.$store.getters.doneTodosCount }}通过方法访问:getters:{ //… getTodoById:(state)=>(id)=>{ return state.todos.find(todo=>todo.id === id) }}store.getters.getTodoById(2)//{id:2,text:’…’,done:false}注意,getter在通过方法访问时,每次都会去进行调用,而不会缓存结果。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’})