Vuex

197 阅读4分钟

什么是Vuex

  • 官方解释:Vuex是一个专门为Vue.js应用程序开发的状态管理模式
    • 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发变化
    • Vuex也集成到Vue的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级功能
  • 状态管理到底是什么?
    • 状态管理模式集中式存储管理这些名词听起来就非常高大上,让人捉摸不透
    • 其实,可以简单的将其看成把需要多个组件共享的变量全部存储在一个对象里
    • 然后将这个对象放在顶层的Vue实例中,让其他组件可以使用
    • 那么,多个组件是不是就可以共享这个对象中的所有变量属性了呢?
  • 等等,如果是这样的,**为什么官方还要专门出一个插件Vuex呢?**难道我们不能自己封装一个对象来管理吗?
    • 当然可以,只是我们要先想想Vue.js带给我们最大的便利是什么呢?没错,就是响应式
    • 如果你自己封装实现一个对象能不能保证它里面所有的属性做到响应式呢?当然也可以,只是自己封装稍微麻烦一些
    • 不用怀疑,Vuex就是为了提供这样一个在多个组件间共享状态的插件,用它就可以了

管理什么状态

  • 有什么状态是需要我们在多个组件间共享的呢?
    • 如果你做过大型开发,你一定遇到过多个状态,在多个界面共享的问题
    • 比如用户的登录状态、用户名称、头像、地理位置信息等等
    • 比如商品的收藏、购物车中的物品等等
    • 这些状态信息,我们都可以放在统一的地方,对它进行保存和管理,而且它们还是响应式

安装和使用

npm install vuex --save

一般在src目录下新建一个store文件夹,再在其中新建一个index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
    state:{
            //这里写一些需要共享的数据
    //这里的所有数据都会加入到响应式系统,包括对象中的属性
    //但是直接新增的对象属性和通过delete删除的属性没有加入响应式系统
    //所以使用 Vue.set(对象,新属性,值) Vue.delete(对象,待删属性)
    //用之前学过的支持响应式的方法均可以
    },
    mutations:{
    //这里写一些方法来修改数据,修改的方法会被 devtools 追踪到
    //如果写异步方法修改数据,那么数据会修改,但是 devtools 不会监测到数据变化
        incrementByCount(s,payload){//第二个参数为组件中 $store.commit('incrementByCount',5) 中的5
            s.counter+=payload
        },
    //参数count这种被称作mutations的负载(载荷Payload)
    //commit的两种风格
        //1.上面那个
        //2.$store.commit({ type : 'incrementByCount',count : 5  })
            //这种方式传入的count是个对象,在上面的方法中要用payload.count

    //因为这些方法名,需要在vue文件中使用,为了不出错要复制或者认真手打
    //可以在store目录下建一个mutations-types.js文件 export const INCREMENT='incrementByCount'
    //这样导入 import { INCREMENT } from './mutation-types.js'
    //就可以使用 [INCREMENT](){} 形式编写方法,在vue文件中,也是 $store.commit(INCREMENT) 使用,不容易出错
    },
    actions:{
//这里写一些异步操作来修改数据
        updateInfo(context,payload){//这里的context为store对象本身
            setTimeout(() =>{
                context.commit('increment')
            },1000)//可以试着用一下返回promise,在vue中使用then来执行修改完后该执行的函数
        }
//vue文件中
//<button @click="$store.dispatch('updateInfo','我是payload')">+</button> 使用dispatch
    },
    getters:{//相当于computed计算属性
        PowerCounter(s,g){//第二个参数为getters本身
          return s.counter * s.counter
        },
        //$store.getters.PowerCounter 使用
        someMethod(s,g){
          return function(arg){
            return s.counter + arg
          }
        }
//$store.getters.someMethod(参数) 使用
    },
    modules:{
    //这里可以存放的属性也是对象,这对象中也有state,mutations,action,getters,modules
        a:{
            state:{
            //state中的属性,在vue文件中 $store.a进行访问,这里的属性不要和外面state内属性名重复
            },
            mutations:{
            //在vue文件中还是 $store.commit()提交
            //若commit()中的方法会从外部先找,找不到再找这里
            },
            actions:{
            //这里context就是指这个a对象,另外还有很多属性,可以尝试着打印一下
            //有rootState,rootGetters等等
            },
            getters:{
            //getters里计算属性的第一个参数state是同层的state
            //第二个参数是getters也是这个getters本身
            //还有第三个参数RootGetters 表示根的getters
            },
            modules:{}
        }
    }
})

export default store

记得在main.js中挂载store

import Vue from 'vue'
import App from './App'
import store from './store'
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
	store,//挂载
  render: h => h(App)
})

在组件中使用this.$store使用,但是官方不推荐直接对this.$store.state进行修改

安装devtools

​ 首先必须要在Chrome上使用,去百度云找找crx文件,将crx文件改为zip文件,解压。打开Chrome的扩展管理,开发者模式下的加载已解压的扩展程序

​ 安装完毕之后,在Chrome里面的开发者模式的标签栏中就会有Vue标签栏。

修改state中的数据

​ 之前说过不推荐直接修改this.$store.state中的值。

推荐做法:在storemutations中定义修改state数据的方法。在组件中使用this.$store.commit('方法名')进行修改,这样修改后都会被devtools所追踪。

//Vuex下的index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
    state:{
        counter:50
    },
    mutations:{
        increment(s){//所有方法的第一个参数都是store对象的state
            s.counter++;
        }
    },
    actions:{},
    getters:{

    },
    modules:{}
})

export default store
<!-- hello.vue -->
<template>
    <div>
        <h2>这是hello组件</h2>
        <span>{{$store.state.counter}}</span>
        <button @click="$store.commit('increment')">+</button>
    </div>
</template>

<script>
    export default {
        name:'hello'
    }
</script>

<style>
</style>

单一状态树

​即单一数据源,就是将所有的状态信息保存到一个store对象中,便于管理。

store夹文件的目录结构

  • store
    • index.js 一般state不抽离,将下面的js文件导入再挂载
    • actions.js
    • mutations.js
    • getters.js
    • modules
      • moduleA.js
      • moduleB.js