经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » HTML/CSS » HTML5 » 查看文章
vuex 源码解析(四) mutation 详解
来源:cnblogs  作者:大沙漠  时间:2019/9/12 10:14:39  对本文有异议

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里包含的是同步操作

例如:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
  7. <script src="https://unpkg.com/vuex@3.1.0/dist/vuex.js"></script>
  8. </head>
  9. <body>
  10.  
  11. <div id="app">
  12. <p>{{no}}</p>
  13. <button @click="test1">测试1</button>
  14. <button @click="test2">测试2</button>
  15. </div>
  16. <script>
  17. const store = new Vuex.Store({
  18. state:{no:100},
  19. mutations:{
  20. increment(state,payload){state.no+=payload.no;}
  21. }
  22. })
  23. var app = new Vue({
  24. el:"#app",
  25. store:store,
  26. computed:{
  27. no(){return this.$store.state.no }
  28. },
  29. methods:{
  30. test1(){
  31. this.$store.commit('increment',{no:100}) //一般调用mutation的方法
  32. },
  33. test2(){
  34. this.$store.commit({type:'increment',no:100}) //mutation的另一种写法
  35. },
  36. }
  37. })
  38. </script>
  39.  
  40. </body>
  41. </html>

 

源码分析


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

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

 registerMutation用于注册mutation的,如下:

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

writer by:大沙漠 QQ:22969969

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

 

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

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

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

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

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

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

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

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

原文链接:http://www.cnblogs.com/greatdesert/p/11424193.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号