欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

vuex 源码分析(六) 辅助函数 详解

程序员文章站 2022-12-07 11:11:17
对于state、getter、mutation、action来说,如果每次使用的时候都用this.$store.state、this.$store.getter等引用,会比较麻烦,代码也重复和冗余,我们可以用辅助函数来帮助我们生成要的代码,辅助函数有如下四个: mapState(namespace, ......

对于state、getter、mutation、action来说,如果每次使用的时候都用this.$store.state、this.$store.getter等引用,会比较麻烦,代码也重复和冗余,我们可以用辅助函数来帮助我们生成要的代码,辅助函数有如下四个:

    mapstate(namespace, map)        ;用于获取state
    mapgetters(namespace, map)       ;用于获取getters
    mapmutations(namespace, map)      ;用于获取mutations
    mapactions(namespace, map)          ;用于获取actions

每个辅助函数都可以带两个参数:

  namespace     ;命名空间,也就是模块名

  map       ;要获取的信息

map有两种用法,可以是对象(键名是当前vue实例设置的变量名,值是从store要获取的变量名)或者字符串数组(此时获取和设置的变量名为同一个)。

注:使用辅助函数需要在根节点注入store

ps:很多新手可能只会使用辅助函数,不知道还可以用this.$store.state,this.$store.getter这些用法...

这些辅助函数返回的都是一个对象,我们可以配合es6的对象展开运算符,我们可以极大地简化写法,例如:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    <script src="https://unpkg.com/vuex@3.1.0/dist/vuex.js"></script>
</head>
<body>
    <div id="app">
        <p>{{no}}</p>
        <p>{{no}}</p>
        <button @click="test1">测试1</button>
        <button @click="test2">测试2</button>
    </div>
    <script>
        const store = new vuex.store({
            state:{no:100},
            getters:{
                no:function(state){return state.no+100}
            },
            mutations:{
                increment(state,payload){state.no+=payload.no;}
            },
            actions:{
                increment({commit},info){
                    settimeout(function(){
                        commit('increment',info)
                    },500)
                }
            }
        })
        var app = new vue({
            el:"#app",
            store,
            computed:{
                ...vuex.mapstate(['no']),
                ...vuex.mapgetters(['no'])
            },
            methods:{
                ...vuex.mapmutations(['increment']),
                ...vuex.mapactions({increment1:"increment"}),
                test1(){
                    this.increment({no:100})
                },
                test2(){
                    this.increment1({no:200})
                }
            }
        })  
    </script>
</body>
</html>

writer by:大沙漠 qq:22969969

我觉得吧,如果用到的vuex里的属性比较多还好一点,如果只用到一个state还不如用this.$store.state来获取呢,毕竟在node环境下还需要import{mapstate} from 'vuex'来获取导出的符号,可以看页面具体的需求选择合理的方法。

 

源码分析


 vuex内的所有辅助函数格式都一样,都是执行一个normalizenamespace()函数,并传入一个匿名函数,该匿名函数带有两个参数,分别是namespace和map,以mapstate为例,如下:

var mapstate = normalizenamespace(function (namespace, states) {        //state辅助函数 name:命名空间 states:比如:count2: "count"
  var res = {};
  normalizemap(states).foreach(function (ref) {                             //将states转换为对象格式,例如:[{key:count2,val:count}]
    var key = ref.key;
    var val = ref.val;

    res[key] = function mappedstate () {                                      //计算属性对应的是一个函数,该函数内的this指向的是vue实例
      var state = this.$store.state;                                              //获取state对象
      var getters = this.$store.getters;                                          //获取getters对象
      if (namespace) {
        var module = getmodulebynamespace(this.$store, 'mapstate', namespace);
        if (!module) {
          return
        }
        state = module.context.state;
        getters = module.context.getters;
      }
      return typeof val === 'function'                                        
        ? val.call(this, state, getters)                                      //state是函数时的逻辑,获取子模块的state会执行到这里
        : state[val]                                                          //返回state[val],也就是值
    };
    // mark vuex getter for devtools
    res[key].vuex = true;
  });
  return res
});

normalizenamespace是统一的一个入口,用于格式化所有的辅助函数,如下:

function normalizenamespace (fn) {                          //返回一个匿名函数,需要两个参数,分别是命名空间和映射,参数1可以省略
  return function (namespace, map) {
    if (typeof namespace !== 'string') {                          //如果参数1不是字符串(即忽略了命名空间)
      map = namespace;                                              //则修正参数1为map
      namespace = '';                                               //重置命名空间为null
    } else if (namespace.charat(namespace.length - 1) !== '/') {
      namespace += '/';
    }
    return fn(namespace, map)                                     //最后执行fn函数
  }
}

其它几个辅助函数都差不多,就是传给normalizenamespace的函数内实现略有不同。