Vue - vuex详解

vuex介绍

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

vuex使用

  • 安装vuex

    1
    npm i vuex --save
  • 创建仓库文件src/store/index.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    import Vue  from "vue";
    import Vuex from "vuex";
    // 安装插件
    Vue.use(Vuex);

    // 实例化一个仓库对象
    let store = new Vuex.Store({
    state:{},
    getters:{},
    mutations:{},
    actions:{},
    modules:{}
    })

    // 暴露
    export default store;
  • 在main.js中引入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import Vue from 'vue'
    import App from './App'
    import router from './router'

    // 引入Store
    import store from "./store"

    Vue.config.productionTip = false

    /* eslint-disable no-new */
    new Vue({
    el: '#app',
    router,
    store, // 挂载到vue实例上面去
    components: { App },
    template: '<App/>'
    })

    一旦将vuex仓库实例挂载到vue实例上面,所有的组件的this里面都会出现一个$store,表示这个仓库实例对象

核心概念

state

  • 作用: 类似于所有组件的data,所有组件都可以在这里读取数据,实现共享

  • 使用:

    1
    2
    3
    4
    5
    6
    let store = new Vuex.Store({
    state:{
    key:val,
    key2:val2
    }
    })
  • 组件模板中

    1
    {{ $store.state.key }}
  • 利用辅助函数 mapState

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 组件中
    import { mapState } from "vuex"

    export default {
    ...,
    computed:{
    ...mapState(['key','key2'])
    }
    }
    // 组件模板中
    {{key}}
    {{key2}}

getters

  • 作用:对仓库里面state数据进行一些加工处理。功能类似组件的computed。

  • 实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    let store = new Vuex.Store({
    state:{
    key:val,
    key2:val2
    },
    getters:{
    newkey(state){
    return state.key+'xxx处理'
    }
    }
    })
  • 组件模板中

    1
    {{$store.getters.newkey}}
  • 利用辅助函数 mapGetters

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 组件中
    import { mapGetters } from "vuex"

    export default {
    ...,
    computed:{
    ...mapGetters(['newkey'])
    }
    }
    // 组件模板中
    {{newkey}}

mutations

  • 作用: vuex中唯一一个可以修改state里面数据的方法。切记不可以通过在组件中赋值state进行修改

    1
    this.$store.state.key = newval    // 错误的写法
  • 使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    let store = new Vuex.Store({
    state:{
    key:val,
    key2:val2
    },
    mutations:{
    // 形参1是state数据 形参2是调用该方法传入的实参
    FN(state,data){
    state.key = data
    }
    }
    })

    组件中实现

    1
    $store.commit('FN',实参)
  • 利用辅助函数 mapMutations

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 组件中
    import { mapMutations } from "vuex"

    export default {
    ...,
    methods:{
    ...mapMutations(['FN'])
    }
    }
    // 组件模板中
    @click="FN(实参)"

actions

  • 作用: 用来修改state。 但是确实间接修改, 他是通过触发mutations里面的方法去修改state 。 actions里面通常存放大量的异步逻辑请求代码。成功之后将数据给muations,然后mutations设置给state。

  • 使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    let store = new Vuex.Store({
    state:{
    key:val,
    key2:val2
    },
    mutations:{
    // 形参1是state数据 形参2是调用该方法传入的实参
    FN(state,data){
    state.key = data
    }
    },
    actions:{
    // 形参1是store,就是这个仓库实例对象。 形参2是调用该方法传入的实参
    fn(store,info){
    store.commit('FN',info)
    }
    }
    })

    组件中实现

    1
    $store.dispatch('fn',实参)
  • 利用辅助函数 mapActions

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 组件中
    import { mapActions } from "vuex"

    export default {
    ...,
    methods:{
    ...mapActions(['fn'])
    }
    }
    // 组件模板中
    @click="fn(实参)"
  • 注意:actions和mutations的区别

    • ​ mutations 是唯一修改state的方法,且是同步修改
    • actions是间接修改state(通过触发mutations), actions里面存放异步处理逻辑

思路图

modules

  • 针对于大型项目放在一个根模块,状态的维护困难。
  • 对于不同项目不同模块的状态管理我们往往存放不同模块中,这样易于维护便于管理。

写法

  • 结构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // store/index.js文件
    let store = new Vuex.Store({
    state:{ 根state },
    getters:{ 根getters },
    mutations:{ 根mutations },
    actions:{ 根actions },
    modules:{
    模块名1:{
    namespaced:false/true, // 不写就是false
    state:()=>({ 模块state }), // 注意模块的state是一个函数,且这个函数返回一个对象
    getters:{ 模块getters },
    mutations:{ 模块mutations },
    actions:{ 模块actions },
    modules:{ 子模块 }
    },
    模块名2:{
    namespaced:false/true, // 不写就是false
    state:()=>({ 模块state }),
    getters:{ 模块getters },
    mutations:{ 模块mutations },
    actions:{ 模块actions },
    modules:{ 子模块 }
    }
    }
    })
  • 真实结构:

    • store目录

      • index.js 仓库对象 【文件】

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        // 导入根配置
        import state from "./state"
        import getters from "./getters"
        import mutations from "./mutations"
        import actions from "./actions"

        // 导入模块
        import 模块1 from "./模块名1"
        import 模块2 from "./模块名2"

        let store = new Vuex.Store({
        state:state,
        getters:getters,
        mutations:mutations,
        actions:actions,
        modules:{
        模块名1:模块1,
        模块名2:模块2
        }
        })
      • state.js 【文件】

        1
        2
        3
        4
        //  根state
        export default {
        key:val
        }
      • getters.js 【文件】

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        // 根getters
        export default {
        newkey(state){ // state 根state state.模块名1 模块1的所有state state.模块名2 模块2的所有state
        return state.key
        }
        newkey(state){
        return state.模块名1.key
        }
        newkey2(state){
        return state.模块名2.key
        }
        }
      • mutations.js 【文件】

        1
        2
        3
        4
        5
        6
        7
        8
        // 根mutations
        export default {
        // 自己的state, 和调用该方法传入的实参
        FN(state,data){
        state.key = data;
        },
        ...
        }
      • actions.js 【文件】

        1
        2
        3
        4
        5
        6
        7
        8
        // 根actions
        export default {
        // store就是仓库实例对象 , 和调用该方法传入的实参
        fn(store,info){
        store.commit('FN',info)
        },
        ...
        }
      • modules 【文件夹】

        • 模块名1.js

          1
          2
          3
          4
          5
          6
          7
          export default {
          state:()=>({ 模块state }),
          getters:{ 模块getters },
          mutations:{ 模块mutations },
          actions:{ 模块actions },
          modules:{ 子模块 }
          }
        • 模块名2.js

获取数据

  • 获取state

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    {{$store.state.key}}    // 去根state里面的数据
    {{$store.state.模块名.key}} // 去某个模块state里面的数据

    // state结构
    state:{
    key:val,
    key2:val2,
    模块名:{
    key:val,
    key2:val2
    }
    }
  • 获取getters

    1
    2
    3
    4
    {{$store.getters.key}}    // 去根getters里面的数据
    {{$store.getters.key2}} // 去某个模块里面getter的数据

    // 所有的getters 都会被挂载到根getters上面

namespaced:false

  • 命名空间没有。没有命名空间的时候,所有的actions最后都是在根actions上面了。所有的mutations都到根mutations上面了。

  • 组件中

    1
    2
    3
    4
    ...mapState({
    key:'key', // 根的,取根state里面的key
    key2:state=>state.模块名.key2 // 取模块的, 去模块state里面的key2
    })
    1
    ...mapGetters(['key1','key2'])   // key1是根getters里面,key2是模块getters里面key2
    1
    2
    3
    $store.commit('任意模块的mutations里面的方法',实参)

    ...mapMutations(['FN1','FN2']) // FN1是根mutations里面的方法, FN2是模块里面的mutations里面的方法
    1
    2
    3
    $store.dispatch('任意模块的actions里面的方法',实参)

    ...mapActions(['fn1','fn2']) // fn1是根actions里面的方法, fn2是模块里面的actions里面的方法
  • 模块中(actions里面方法里)调用其他模块的mutations或actions里面的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // A模块
    {
    ...,
    mutations:{
    FN(state,data){
    state.key = data
    }
    },
    actions:{
    fn(store,info){
    store.commit('FN',info) // 触发自己的mutations里面的方法
    store.dispatch('fn2') // 触发自己的actions里面的其他方法

    // A模块触发B模块里面的方法 缺点: 无法区分调用的方法是哪个模块的 对于大型项目而言,非常的混乱
    store.commit('FN3',info)
    store.dispatch('fn3',info)

    }
    fn2(store,info){...}
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //B模块
    {
    ...,
    mutations:{
    FN3(state,data){
    state.key = data
    }
    },
    actions:{
    fn3(store,info){
    store.commit('FN3',info) // 触发自己的mutations里面的方法FN3
    store.dispatch('fn4') // 触发自己的actions里面的其他方法fn4
    }
    fn4(store,info){...}
    }
    }

namespaced:true

  • 命名空间有

  • 组件中

    1
    2
    3
    4
    ...mapState({
    key:'key', // 根的,取根state里面的key
    key2:state=>state.模块名.key2 // 取模块的, 去模块state里面的key2
    })
    1
    2
    3
    4
    ...mapGetters({
    key1:'key1' // key1是根getters里面
    key2:'模块名/key2' // key2是模块getters里面key2
    })
    1
    2
    3
    4
    5
    6
    $store.commit('模块名/该模块mutations里面的方法',实参)

    ...mapMutations({
    FN1:'FN1', // FN1是根mutations里面的方法
    FN2:'模块名/FN2' // FN2是模块里面的mutations里面的方法
    })
    1
    2
    3
    4
    5
    6
    $store.dispatch('模块名/该模块actions里面的方法',实参)

    ...mapActions({
    fn1:'fn1', // fn1是根actions里面的方法
    fn2:'模块名/fn2' // fn2是模块里面的actions里面的方法
    })
  • 模块中(actions里面方法里)调用其他模块的mutations或actions里面的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    // A模块
    {
    ...,
    mutations:{
    FN(state,data){
    state.key = data
    }
    },
    actions:{
    fn(store,info){
    store.commit('FN',info) // 触发自己的mutations里面的方法
    store.dispatch('fn2') // 触发自己的actions里面的其他方法

    // A模块触发B模块里面的方法
    store.commit('模块名/FN3',info,{root:true})
    store.dispatch('模块名/fn3',info,{root:true})

    // store相关信息
    // store.state 当前模块的state
    // store.getters 当前模块的getters
    // store.commit 调用任意模块的muations,注意模块名,root:true
    // store.dispatch 调用任意模块的actions,注意模块名,root:true
    // store.rootState 根state
    // store.rootGetters 根getters

    }
    fn2(store,info){...}
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //B模块
    {
    ...,
    mutations:{
    FN3(state,data){
    state.key = data
    }
    },
    actions:{
    fn3(store,info){
    store.commit('FN3',info) // 触发自己的mutations里面的方法FN3
    store.dispatch('fn4') // 触发自己的actions里面的其他方法fn4
    }
    fn4(store,info){...}
    }
    }