成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Vue源碼解析(五)-vuex

calx / 2029人閱讀

摘要:提供了函數(shù),它把直接映射到我們的組件中,先給出的使用值為值為讓我們看看的源碼實(shí)現(xiàn)規(guī)范當(dāng)前的命名空間。在中,都是同步事務(wù)。同步的意義在于這樣每一個(gè)執(zhí)行完成后都可以對應(yīng)到一個(gè)新的狀態(tài)和一樣,這樣就可以打個(gè)存下來,然后就可以隨便了。

Vue 組件中獲得 Vuex 狀態(tài)

按官網(wǎng)說法:“由于 Vuex 的狀態(tài)存儲是響應(yīng)式的,從 store 實(shí)例中讀取狀態(tài)最簡單的方法就是在計(jì)算屬性中返回某個(gè)狀態(tài)”,本文結(jié)合下面的demo進(jìn)行分析:

import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex)
const vueStore = new Vuex.Store({
    state: {
        count: 0
    },
    mutations: {
        increment (state) {
            state.count++
        }
    }
})
let vm = new Vue({
    el: "#app",
    store: vueStore,
    template: "
{{count}}
", computed: { count(){ return this.$store.state.count } } })

下面主要分析為什么可以通過this.$store直接訪問vueStore對象。先看看Vue.use方法

  Vue.use = function (plugin) {
    //插件只能注冊一次
    var installedPlugins = (this._installedPlugins || (this._installedPlugins = []));
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    }
    
    //拼接參數(shù),將Vue作為第一個(gè)參數(shù)
    // additional parameters
    var args = toArray(arguments, 1);
    args.unshift(this);
    
    //調(diào)用plugin.install或plugin方法
    if (typeof plugin.install === "function") {
      plugin.install.apply(plugin, args);
    } else if (typeof plugin === "function") {
      plugin.apply(null, args);
    }
    installedPlugins.push(plugin);
    return this
  };

再看Vuex源碼,Vuex其實(shí)是下面這個(gè)對象

{
  Store: Store,
  install: install,
  mapState: mapState,
  mapMutations: mapMutations,
  mapGetters: mapGetters,
  mapActions: mapActions,
  createNamespacedHelpers: createNamespacedHelpers
}

因此Vue.use(Vuex)其實(shí)想到于Vuex.install()

let Vue; // bind on install
function install (_Vue) {
  Vue = _Vue;
  applyMixin(Vue);
}

var applyMixin = function (Vue) {
  var version = Number(Vue.version.split(".")[0]);
  //Vue2.0處理方法
  if (version >= 2) {
    //將vuexInit方法注冊到beforeCreate鉤子上,當(dāng)Vue的生命周期走到callHook(vm, "beforeCreate");時(shí)觸發(fā)vuexInit方法
    Vue.mixin({ beforeCreate: vuexInit });
  } 

  // Vuex init hook, injected into each instances init hooks list.
  function vuexInit () {
    //this就是當(dāng)前正在被new的Vue對象
    var options = this.$options;
    //將options.store(本例demo中的vueStore)賦值給this.$store,因此可以通過this.$store訪問vueStore對象
    // store injection
    if (options.store) {
      this.$store = typeof options.store === "function"
        ? options.store()
        : options.store;
    } else if (options.parent && options.parent.$store) {
      this.$store = options.parent.$store;
    }
  }
}
mapState

通過computed屬性可以獲取到狀態(tài)值,但是每一個(gè)屬性都要通過this.$store.state訪問不是很方便。vue 提供了 mapState 函數(shù),它把state直接映射到我們的組件中,先給出mapState的使用demo

let mapState = Vuex.mapState
let vm = new Vue({
  el: "#app",
  store: vueStore,
  template:
  `
`, components:{ "my-component":{ template: "
{{count}}-{{num}}
", computed: mapState({ // {{count}}值為this.$store.state.count count: state => state.count, // {{num}}值為this.$store.state.num, num: "num"          }) } } })

讓我們看看mapState的源碼實(shí)現(xiàn)

//normalizeNamespace規(guī)范當(dāng)前vuex的命名空間。默認(rèn)情況下,vuex內(nèi)部的 action、mutation 和 getter 是注冊在全局命名空間的,本例也是,因此namespace=‘’
var mapState = normalizeNamespace(function (namespace, states) {
  var res = {};
  //規(guī)范states參數(shù),將states轉(zhuǎn)換為map格式,因此mapState支持多種寫法
  normalizeMap(states).forEach(function (ref) {
    var key = ref.key;
    var val = ref.val;
    res[key] = function mappedState () {
      var state = this.$store.state;
      var getters = this.$store.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[val]
    };
    // mark vuex getter for devtools
    res[key].vuex = true;
  });
  //mapState其實(shí)就是提供簡潔的寫法將this.$store.state[val]賦值給coputed屬性
  return res
});

function normalizeMap (map) {
  return Array.isArray(map)
    ? map.map(function (key) { return ({ key: key, val: key }); })
    : Object.keys(map).map(function (key) { return ({ key: key, val: map[key] }); })
}
//規(guī)范當(dāng)前vuex的命名空間
function normalizeNamespace (fn) {
  return function (namespace, map) {
    if (typeof namespace !== "string") {
      map = namespace;
      namespace = "";
    } else if (namespace.charAt(namespace.length - 1) !== "/") {
      namespace += "/";
    }
    return fn(namespace, map)
  }
}
store響應(yīng)式原理

Vue源碼解析(二)中介紹過data的響應(yīng)式原理:
1、對data進(jìn)行observe,針對data屬性調(diào)用Object.defineProperty設(shè)置getter和setter,同時(shí)綁定一個(gè)dep對象
2、new Watcher(vm, updateComponent, noop)監(jiān)聽整個(gè)dom的變化
3、watcher初始化時(shí)調(diào)用updateComponent,updateComponent調(diào)用render函數(shù)更新dom(此時(shí)還會將該watcher對象賦值給全局對象Dep.target,進(jìn)行依賴收集)
4、在watcher對象依賴收集期間,render函數(shù)訪問data中的屬性(如本例的data.message),觸發(fā)data.message的getter方法,在getter方法中會將data.message綁定的dep對象和wathcer對象建立對應(yīng)關(guān)系(互相加入到對方維護(hù)的隊(duì)列屬性上)
5、后續(xù)data屬性的值變化時(shí)dep對象會通知所有依賴此data屬性的watcher對象調(diào)用updateComponent方法更新視圖
store響應(yīng)式的原理也是類似的,new Vuex.Store的過程也會對state進(jìn)行observe

var Store = function Store (options) {
    var state = options.state
    //為了實(shí)現(xiàn)state的響應(yīng)性new一個(gè)vue對象
    // initialize the store vm, which is responsible for the reactivity
    resetStoreVM(this, state);
}
function resetStoreVM (store, state, hot) {
  //new一個(gè)vue對象對data(值為store.state)進(jìn)行監(jiān)聽
  store._vm = new Vue({
    data: {
      $$state: state
    },
    computed: computed
  });
}

后續(xù)實(shí)現(xiàn)和上面的data響應(yīng)式相同

mutation

new Vuex.Store的過程中會將mutation注冊到store._mutations上

function registerMutation (store, type, handler, local) {
  var entry = store._mutations[type] || (store._mutations[type] = []);
  //封裝mutation方法并push到store._mutations[type]上
  entry.push(function wrappedMutationHandler (payload) {
    handler.call(store, local.state, payload);
  });
}

當(dāng)執(zhí)行commit方法時(shí)就會執(zhí)行store._mutations上對應(yīng)的方法

Store.prototype.commit = function commit (type, payload) {
    var entry = this._mutations[type];
    entry.forEach(function commitIterator (handler) {
        handler(payload);
    });
}
actions
const vueStore = new Vuex.Store({
    state: {
        count: 1,
    },
    mutations: {
        increment (state,payload) {
            state.count+=payload
        }
    },
    actions: {
        increment (context,payload) {
            setTimeout(function () {
                context.commit("increment",payload)
            },1000)
        }
    }
})
vueStore.dispatch("increment",10)

和mutation一樣,new Vuex.Store也會將action注冊到store._actions上,然后通過dispatch調(diào)用

function registerAction (store, type, handler, local) {
  var entry = store._actions[type] || (store._actions[type] = []);
  //包裝action方法,傳入store對象的commit方法和state等等
  entry.push(function wrappedActionHandler (payload, cb) {
    var res = handler.call(store, {
      dispatch: local.dispatch,
      commit: local.commit,
      getters: local.getters,
      state: local.state,
      rootGetters: store.getters,
      rootState: store.state
    }, payload, cb);
    //action的返回不是promise會返回Promise.resolve(res)
    if (!isPromise(res)) {
        res = Promise.resolve(res);
    }
    return res
  });
}

Store.prototype.dispatch = function dispatch (_type, _payload) {
  var entry = this._actions[type];
  return entry.length > 1
    ? Promise.all(entry.map(function (handler) { return handler(payload); }))
    : entry[0](payload)
};

看到action和mutation的源碼實(shí)現(xiàn),你不禁要問了,這不是基本一樣的嗎,那干嘛還要多此一舉?
vuex官網(wǎng)的解釋:在 mutation 中混合異步調(diào)用會導(dǎo)致你的程序很難調(diào)試。例如,當(dāng)你能調(diào)用了兩個(gè)包含異步回調(diào)的 mutation 來改變狀態(tài),你怎么知道什么時(shí)候回調(diào)和哪個(gè)先回調(diào)呢?這就是為什么我們要區(qū)分這兩個(gè)概念。在 Vuex 中,mutation 都是同步事務(wù)。
知乎上有個(gè)問題“vuex中為什么把把異步操作封裝在action,把同步操作放在mutations?“,vue的作者尤雨溪的解釋:事實(shí)上在 vuex 里面 actions 只是一個(gè)架構(gòu)性的概念,并不是必須的,說到底只是一個(gè)函數(shù),你在里面想干嘛都可以,只要最后觸發(fā) mutation 就行。異步競態(tài)怎么處理那是用戶自己的事情。vuex 真正限制你的只有 mutation 必須是同步的這一點(diǎn)(在 redux 里面就好像 reducer 必須同步返回下一個(gè)狀態(tài)一樣)。
同步的意義在于這樣每一個(gè) mutation 執(zhí)行完成后都可以對應(yīng)到一個(gè)新的狀態(tài)(和 reducer 一樣),這樣 devtools 就可以打個(gè) snapshot 存下來,然后就可以隨便 time-travel 了。
我個(gè)人的理解這是vuex的使用規(guī)范問題,mutation中使用異步也不會有大問題,但是按規(guī)范開發(fā)能讓項(xiàng)目結(jié)構(gòu)更清晰,調(diào)試更方便,下圖是用vue devtool調(diào)試的vuex官方例子(https://github.com/vuejs/vuex...),mutation的觸發(fā)時(shí)間線一目了然

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/89885.html

相關(guān)文章

  • 關(guān)于Vue2一些值得推薦的文章 -- 、六月份

    摘要:五六月份推薦集合查看最新的請點(diǎn)擊集前端最近很火的框架資源定時(shí)更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥雀呼晴,侵曉窺檐語。葉上初陽乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門,久作長安旅。五月漁郎相憶否。小楫輕舟,夢入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時(shí)更新,歡迎 Star 一下。 蘇...

    sutaking 評論0 收藏0
  • 關(guān)于Vue2一些值得推薦的文章 -- 、六月份

    摘要:五六月份推薦集合查看最新的請點(diǎn)擊集前端最近很火的框架資源定時(shí)更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥雀呼晴,侵曉窺檐語。葉上初陽乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門,久作長安旅。五月漁郎相憶否。小楫輕舟,夢入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時(shí)更新,歡迎 Star 一下。 蘇...

    khs1994 評論0 收藏0
  • 前方來報(bào),八月最新資訊--關(guān)于vue2&3的最佳文章推薦

    摘要:哪吒別人的看法都是狗屁,你是誰只有你自己說了才算,這是爹教我的道理。哪吒去他個(gè)鳥命我命由我,不由天是魔是仙,我自己決定哪吒白白搭上一條人命,你傻不傻敖丙不傻誰和你做朋友太乙真人人是否能夠改變命運(yùn),我不曉得。我只曉得,不認(rèn)命是哪吒的命。 showImg(https://segmentfault.com/img/bVbwiGL?w=900&h=378); 出處 查看github最新的Vue...

    izhuhaodev 評論0 收藏0
  • Vue.js資源分享

    摘要:中文官網(wǎng)英文官網(wǎng)組織發(fā)出一個(gè)問題之后,不要暫時(shí)的離開電腦,如果沒有把握先不要提問。珍惜每一次提問,感恩每一次反饋,每個(gè)人工作還是業(yè)余之外抽出的時(shí)間有限,充分準(zhǔn)備好應(yīng)有的資源之后再發(fā)問,有利于問題能夠高效質(zhì)量地得到解決。 Vue.js資源分享 更多資源請Star:https://github.com/maidishike... 文章轉(zhuǎn)自:https://github.com/maid...

    vpants 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<