mutation是更改Vuex的store中的状态的唯一方法,mutation类似于事件注册,每个mutation都可以带两个参数,如下:

  state     ;当前命名空间对应的state

  payload     ;传入的参数,一般是一个对象

创建Vuex.Store()仓库实例时可以通过mutations创建每个mutation

我们不能直接调用一个mutation,而是通过 store.commit来调用,commit可以带两个参数,如下:

  type     ;对应的mutation名

  payload    ;传入的参数

commit还有一种写法,就是传入一个对象即可,该对象可以带一个type参数,type指定为mutation的名称,整个对象会作为参数传递给mutation。注意:mutation里包含的是同步操作

例如:

<!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>
<button @click="test1">测试1</button>
<button @click="test2">测试2</button>
</div>
<script>
const store = new Vuex.Store({
state:{no:100},
mutations:{
increment(state,payload){state.no+=payload.no;}
}
})
var app = new Vue({
el:"#app",
store:store,
computed:{
no(){return this.$store.state.no }
},
methods:{
test1(){
this.$store.commit('increment',{no:100}) //一般调用mutation的方法
},
test2(){
this.$store.commit({type:'increment',no:100}) //mutation的另一种写法
},
}
})
</script> </body>
</html>

源码分析


在创建Vuex.Store()初始化时会执行installModule()安装根模块,和mutation相关的如下:

  function installModule (store, rootState, path, module, hot) {      //安装模块
/*略*/ module.forEachMutation(function (mutation, key) { //遍历module模块的mutations对象,如果找到了,则执行这个匿名函数 参数1:每个mutation值 key:对应的键名
var namespacedType = namespace + key; //拼凑namespacedType
registerMutation(store, namespacedType, mutation, local); //调用registerMutation注册mutation
});
/*略*/
}

registerMutation用于注册mutation的,如下:

  function registerMutation (store, type, handler, local) {             //注册Mutations
var entry = store._mutations[type] || (store._mutations[type] = []); //如果store对象的_mutations对应的为空,则初始化为数组
entry.push(function wrappedMutationHandler (payload) { //则将一个匿名函数push到entry里面
handler.call(store, local.state, payload); //上下文是store,参数1为local.state,参数2为payload
});
}

writer by:大沙漠 QQ:22969969

也就是说注册完后对应的mutation会存储在store._mutations里,这是一个对象,每个键是一个mutation,而值就是对应的mutation,是个数组,例如例子里执行到这里时对应的_mutation如下:

等到我们调用this.$store.commit('increment',{no:100})去触发一个mutation时首先会触发Store函数内重定义的commit,它会以当前Store函数对象为上下文继续执行Store原型上的commit函数,如下:

  Store.prototype.commit = function commit (_type, _payload, _options) {      //对mutation的处理
var this$1 = this; // check object-style commit
var ref = unifyObjectStyle(_type, _payload, _options); //规范一下参数,返回一个对象,例如:{options: undefined,payload: {no: 100},type: "increment"}
var type = ref.type; //mutagion类型:比如:increment
var payload = ref.payload; //传递过来的参数
var options = ref.options; //选项 var mutation = { type: type, payload: payload };
var entry = this._mutations[type]; //直接从this._mutations里获取type类型的mutaion,是个函数数组
if (!entry) { //如果该mutaion不存在,则报错
{
console.error(("[vuex] unknown mutation type: " + type));
}
return
}
this._withCommit(function () { //在this._withCommit()环境下执行该函数
entry.forEach(function commitIterator (handler) { //遍历entry,依次执行每个handler函数,参数为payload
handler(payload);
});
});
this._subscribers.forEach(function (sub) { return sub(mutation, this$1.state); }); if (
options && options.silent
) {
console.warn(
"[vuex] mutation type: " + type + ". Silent option has been removed. " +
'Use the filter functionality in the vue-devtools'
);
}
};

unifyObjectStyle是一个工具函数,它会修正参数,并返回一个对象,如下:

  function unifyObjectStyle (type, payload, options) {        //统一object的类型
if (isObject(type) && type.type) { //如果type是个类型且含有type属性,比如这样的格式:this.$store.commit({type:'increment',no:1000})
options = payload;
payload = type;
type = type.type;
} {
assert(typeof type === 'string', ("expects string as the type, but found " + (typeof type) + "."));
} return { type: type, payload: payload, options: options } //最后返回该对象
}

我们在例子里可以用两种方式来调用mutation也是这个unifyObjectStyle函数的作用

_withCommit是一个工具函数,如下:

Store.prototype._withCommit = function _withCommit(fn) {                //执行fn函数 执行时设置this._committing为true,执行完后设置为false
var committing = this._committing; //保存this._committing到局部变量committing里
this._committing = true; //设置this._committing为true
fn(); //执行fn函数
this._committing = committing; //恢复this._committing
};

它在执行传入的函数时会设置Store._committing为true,这样就相当于设置了一个标记,表示当前是通过mutation来修改state的,还记得上一节说的strict严格模式吗,它就是通过这里的_committing来判断是否合法的。

vuex 源码解析(四) mutation 详解的更多相关文章

  1. 【源码解析】BlockManager详解

    1 Block管理模块的组件和功能 BlockManager:BlockManager源码解析 Driver和Executor都会创建 Block的put.get和remove等操作的实际执行者 Bl ...

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

    对于state.getter.mutation.action来说,如果每次使用的时候都用this.$store.state.this.$store.getter等引用,会比较麻烦,代码也重复和冗余,我 ...

  3. vuex 源码分析(五) action 详解

    action类似于mutation,不同的是Action提交的是mutation,而不是直接变更状态,而且action里可以包含任意异步操作,每个mutation的参数1是一个对象,可以包含如下六个属 ...

  4. 我的书籍《深入解析Java编译器:源码剖析与实例详解》就要出版了

    一个十足的技术迷,2013年毕业,做过ERP.游戏.计算广告,在大公司呆过,但终究不满足仅对技术的应用,在2018年末离开了公司,全职写了一本书<深入解析Java编译器:源码剖析与实例详解> ...

  5. Mybatis源码解析(四) —— SqlSession是如何实现数据库操作的?

    Mybatis源码解析(四) -- SqlSession是如何实现数据库操作的?   如果拿一次数据库请求操作做比喻,那么前面3篇文章就是在做请求准备,真正执行操作的是本篇文章要讲述的内容.正如标题一 ...

  6. nginx源码分析线程池详解

    nginx源码分析线程池详解 一.前言     nginx是采用多进程模型,master和worker之间主要通过pipe管道的方式进行通信,多进程的优势就在于各个进程互不影响.但是经常会有人问道,n ...

  7. 【集合框架】JDK1.8源码分析之ArrayList详解(一)

    [集合框架]JDK1.8源码分析之ArrayList详解(一) 一. 从ArrayList字表面推测 ArrayList类的命名是由Array和List单词组合而成,Array的中文意思是数组,Lis ...

  8. Sentinel源码解析四(流控策略和流控效果)

    引言 在分析Sentinel的上一篇文章中,我们知道了它是基于滑动窗口做的流量统计,那么在当我们能够根据流量统计算法拿到流量的实时数据后,下一步要做的事情自然就是基于这些数据做流控.在介绍Sentin ...

  9. Spring源码之九finishRefresh详解

    Spring源码之九finishRefresh详解 公众号搜索[程序员田同学],专职程序员兼业余写手,生活不止于写代码 Spring IoC 的核心内容要收尾了,本文将对最后一个方法 finishRe ...

随机推荐

  1. Android方法数超出限定的问题(multiDex,jumboMode)

    在Android项目开发中,项目代码量过大或通过引入很多jar导致代码量急剧增加,会出现错误: android.dex.DexIndexOverflowException: Cannot merge ...

  2. Python爬取6271家死亡公司数据,看十年创业公司消亡史

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 朱小五 凹凸玩数据 PS:如有需要Python学习资料的小伙伴可以加 ...

  3. 用一个bat文件调用另外两个bat文件,当1.bat执行完后再执行2.bat

    用一个bat文件调用另外两个bat文件,当1.bat执行完后再执行2.bat 摘自:https://zhidao.baidu.com/question/492732911.html @echo off ...

  4. 完整版的CAD技巧!3天轻松玩转CAD,零基础也能学会

    最近有很多小伙伴反应,CAD图纸学起来有点小困难,也许你还没能掌握技巧,CAD大神带你3天轻松玩转CAD,零基础也能快速学会. 一.看懂图纸是关键 CAD制图首先得让自己知道要绘制什么,如果心中对图纸 ...

  5. HTML5新标签与特性---多媒体

    多媒体标签 embed:标签定义嵌入的内容 audio:播放音频 video:播放视频 多媒体 embed(会使用) embed可以用来插入各种多媒体,格式可以是 Midi.Wav.AIFF.AU.M ...

  6. 移动端底部导航固定配合vue-router实现组件切换

    在我们平时练习或者实际项目中也好,我们常常遇到这么一个需求:移动端中的导航并不是在顶部也不是在底部,而是在最底部且是固定的,当我们点击该导航项时会切换到对应的组件.相信对于很多朋友而言,这是一个很简单 ...

  7. 查看UNDO 表空间使用情况

    Select Sum(bytes / (1024 * 1024)), a.status    From dba_undo_extents a   Group By a.status Select fi ...

  8. [Go] 分页计算页码的主要逻辑

    当使用imap进行读取邮件体的时候,有个函数可以根据传入的开始和结束索引来一次读取多条邮件内容主要逻辑类似这样,从1开始, 1,10   11,20     21,30 或者 1,31   32,63 ...

  9. fake_useragent.json

    { "browsers": { "chrome": [ "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.3 ...

  10. xml的建模

    xml建模的思路 1.分析需要被建模的文件中有那几个对象 2.每个对象拥有的行为以及属性 3.定义对象从小到大(从里到外) 4.通过23种的设计模式中的工厂模式,解析xml生产出指定对象 建模的好处 ...