Vue中的Vuex(一)

247 阅读4分钟

小编在项目中,经常会使用到Vuex,其实小编自己只是知道Vuex是为了解决什么痛点,但是具体这个东西是怎么回事,小编自己有点迷迷糊糊,昨天小编痛下决心,认认真真的把Vuex的官网(vuex.vuejs.org/zh/) 读了一遍,收获还是很多的,特地拿出来与大家分享,也希望能在大家今后的面试中,增加一些筹码和信心。大家还可以关注我的微信公众号,蜗牛全栈。

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension (opens new window),提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。

这个是官网对Vuex的描述,小编之前的项目经常会用Vuex存储用户信息,比如当前用户的id,用户所在部门,头像等等,这些信息都是通过数据接口获得的数据,其实存储在用户浏览器的Cookie和LocalStorage都是可以的,用的时候,再从本地的相应位置获取,用户退出的时候,清空对应的信息,同样也可以较少多次请求,并且也解决了多个组件共享数据的痛点。但是很多成型的admin都在使用Vuex,同样对于另一个前端框架大名鼎鼎的React也在用类似的方案(Redux),面临前端日新月异的发展,学会使用Vuex就显得更为重要。

Vuex主要分为四个部分,State、Getters、Mutations、Actions,小编下面就结合实例一一的解释一下。在正式进入Vuex的世界之前,我们需要先安装Vuex

npm install vuex --save

在我们使用脚手架构建项目的时候,需要显示的在项目入口文件main.js中引入Vuex,并通过Vue.use()来安装

import Vue from 'vue'import Vuex from 'vuex'
Vue.use(Vuex)

Vuex依赖Promise,还不了解Promise的,可以查看小编之前的文章《ES6中的Promise》

一、State

Vuex核心就是一个store,store中的数据都存放在State中,可以将State理解成一个大仓库,大仓库中存着我们需要共享的数据。在组件中,可以通过this.$store获取State中的数据,为了保证数据的一致性,State中数据是不允许直接修改的,改变 store 中的状态的唯一途径就是显式地提交 (commit)

下面我们来创建一个最简单的store

import Vue from 'vue'
import Vuex from 'vuex'
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

最后,我们需要把store注入到创建的Vue实例中,就像这样

new Vue({  el: '#app',  store // 这个位置因为对象的key和value一样,使用es6语法可以简写成这样})

那么我们如何在 Vue 组件中展示状态呢?由于 Vuex 的状态存储是响应式的,从 store 实例中读取状态最简单的方法就是在计算属性(computed)中返回某个状态:

// 创建一个 Counter 组件
const Counter = {  
    template: `<div>{{ count }}</div>`,  
    computed: {    
        count () {      
            return store.state.count    
        }  
}}

我们还可以这样

const Counter = {  
    template: `<div>{{ count }}</div>`,  
    computed: {    
        count () {      
            return this.$store.state.count    
        }  
}}

实际上以上内容,我们就可以正常读取store中的值了,官方还提供我们一种更简便的方式: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    
    }  
})}

同样,类似es6对象的扩展中,key和value值一样的时候,可以简写,同样,mapState也提供类似的使用方法

computed: mapState([  
    // 映射 this.count 为 store.state.count  
    'count'])

在es6出现了扩展运算符的之后,我们可以更加简便的写法,也是小编在github上最常见的方式

computed: {  
    localComputed () { /* ... */ },  
    // 使用对象展开运算符将此对象混入到外部对象中  
    ...mapState({    // ...  })}

二、Getters

小编个人感觉这个和一些后端语言有类似的地方,比如我们想获取一个store中数组的长度,没有Getters的时候,我们需要在计算属性(computed)这么写

computed: {  
    doneTodosCount () {    
        return this.$store.state.todos.filter(todo => todo.done).length  
    }
}

这个例子还是相对比较简单的,要是遇上更复杂的情况,在获取到State中数据之后,还要各种处理,想想一坨坨的js代码,头就大,还好,Vuex提供了Getters。我们可以这样写

const store = new Vuex.Store({  
    state: {    
        todos: [      
            { id: 1, text: '...', done: true },      
            { id: 2, text: '...', done: false }    
        ]  
    },  
    getters: { // 通过Getters将doneTodos暴露出去    
        doneTodos: state => {      
            return state.todos.filter(todo => todo.done)    
        }  
}})

在获取的时候,这样就可以获取到内容了,就像这样

store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]

Getter 也可以接受其他 getter 作为第二个参数:

getters: {  
// ...  
    doneTodosCount: (state, getters) => {    
        return getters.doneTodos.length  
}}
store.getters.doneTodosCount // -> 1

我们可以很容易地在任何组件中使用它:

computed: {  
    doneTodosCount () {    
        return this.$store.getters.doneTodosCount  
}}

同样,我们还可以让Getters结合es6箭头函数返回一个函数,在实际使用页面中传递参数来获取不同的结果,就类似原生js的过滤器filter一样

getters: {  
    // ...  
    getTodoById: (state) => (id) => {    
        return state.todos.find(todo => todo.id === id)  
}}
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

和上面mapState类似,Getters也提供了类似的方式

import { mapGetters } from 'vuex'
export default {  
    // ...  
    computed: {  
    // 使用对象展开运算符将 getter 混入 computed 对象中    
    ...mapGetters([      
        'doneTodosCount',      
        'anotherGetter',      
        // ...    
    ])  
}}

如果你想将一个 getter 属性另取一个名字,使用对象形式:

...mapGetters({  
    // 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount` 
    doneCount: 'doneTodosCount'
})

参考文献:vuex.vuejs.org/zh/