国产精品爱久久久久久久小说,女人扒开腿让男人桶到爽 ,亚洲欧美国产双大乳头,国产成人精品综合久久久久,国产精品制服丝袜无码,免费无码精品黄av电影,黑色丝袜无码中中文字幕,乱熟女高潮一区二区在线

            Vuex源碼分析

            2019-12-8    seo達人

            一、前言

            我們都知道,vue組件中通信是用props進行父子通信,或者用provide和inject注入的方法,后者類似與redux的porvider,父組件使用,包含在里面的子組件都可以使用,provide/inject用法看我的博客(provide/inject用法),provide/indect官方文檔,不過provide/indect一般用的不多,都是用前者,但是props有一個問題,父傳子沒問題,但是子后面還有子,子后面還有子,子子孫孫無窮盡也,所以這就要一層層的傳下去,太麻煩了,所以vuex就派上用場了,vuex作為一個很輕量的狀態(tài)管理器,有著簡單易用的的API接口,在任意組件里面都能使用,獲取全局狀態(tài),統(tǒng)一獲取改變,今天,就看一下源碼怎么實現的。



            二、準備

            1)先去github上將vuex源碼下載下來。

            2)打開項目,找到examples目錄,在終端,cd進入examples,執(zhí)行npm i,安裝完成之后,執(zhí)行node server.js



            3)執(zhí)行上述之后,會得到下方的結果,表示編譯完成,打開瀏覽器 輸入 localhost:8080



            4) 得到頁面,點擊counter



            5)最終,我們就從這里出發(fā)調試吧。





            三、調試

            找到counter目錄下的store.js 寫一個debugger,瀏覽器打開F12,刷新頁面,調試開始。



            1.Vue.use()

            先進入Vue.use(Vuex),這是Vue使用插件時的用法,官方文檔也說了,Vue.use,會調用插件的install方法,所以如果你要寫插件的話,你就要暴露一個install方法,詳情請看vue官方文檔之use的用法



            即use會調用下方的方法(debugger會進入)



            function initUse (Vue) {

              Vue.use = function (plugin) {

                var installedPlugins = (this._installedPlugins || (this._installedPlugins = []));

                if (installedPlugins.indexOf(plugin) > -1) {

                  return this

                }



                // additional parameters

                var args = toArray(arguments, 1);

                args.unshift(this);

                if (typeof plugin.install === 'function') { 

                // 如果插件的install是一個function,調用install,將 this指向插件,并將Vue作為第一個參數傳入

                // 所以調用vuex吧this指向vuex,并吧vue當參數傳入

                  plugin.install.apply(plugin, args);

                } else if (typeof plugin === 'function') {

                  plugin.apply(null, args);

                }

                installedPlugins.push(plugin);

                return this

              };

            }





            1.1 vuex的install方法

            在源碼目錄的src目錄下的store.js文件里最下方有個install函數,會調用它



            debugger進入后



            export function install (_Vue) { // _Vue是上面說的Vue作為第一個參數 ,指針this指向Vuex

              if (Vue && _Vue === Vue) {

               // 如果你在開發(fā)環(huán)節(jié),你使用了兩次Vue.use(Vuex) 就會報下方的錯誤,提醒你vue只能被use一次,可以自行試試

                if (process.env.NODE_ENV !== 'production') {

                  console.error(

                    '[vuex] already installed. Vue.use(Vuex) should be called only once.'

                  )

                }

                return

              }

              Vue = _Vue

              applyMixin(Vue) // 調用applyMixin方法

            }



            1.2 vuex的applyMixin方法

            applyMixin方法在mixin.js文件里 同樣在src目錄下



            export default function (Vue) {

              const version = Number(Vue.version.split('.')[0]) // 獲取vue的版本



              if (version >= 2) { // vue的版本是2.xx以上 執(zhí)行vue的mixin混入,該函數不懂用法請查看官方文檔,

              // mixin合并混入操作,將vuexInit 方法混入到beforeCreate生命周期,意思就是當執(zhí)行beforeCreate周期的時候

              // 會執(zhí)行vuexInit 方法

                Vue.mixin({ beforeCreate: vuexInit })

              } else { // 1.xxx版本太老了 現在基本不用,暫不講解,可以自行了解

                // override init and inject vuex init procedure

                // for 1.x backwards compatibility.

                const _init = Vue.prototype._init

                Vue.prototype._init = function (options = {}) {

                  options.init = options.init

                    ? [vuexInit].concat(options.init)

                    : vuexInit

                  _init.call(this, options)

                }

              }



              /*

               
            Vuex init hook, injected into each instances init hooks list.

               /



              function vuexInit () { 

              // 因為該方法是在beforeCreate下執(zhí)行,而beforeCreate的this指向為Vue 所以this === Vue

              // 獲得vue里面的option配置,這里涉及到vue的源碼,以后再講vue ,

              //所以這就是我們?yōu)槭裁匆趎ew Vue的時候,傳遞一個store進去的原因,

              //因為只有傳進去,才能在options中獲取到store

              /


              var vm = new Vue({

            el: "#app",

            data() {return{}},

            store

            })

            */

                const options = this.$options

                // store injection

                if (options.store) { 

                // 如果options對象中store有,代表是root ,如果options.store是函數,執(zhí)行調用options.store()

                // 如果是對象直接options.store 賦值給this.$stroe

              // 這也就是我們?yōu)槭裁茨軌蛟赩ue項目中直接this.$store.disptach('xxx')的原因,從這里獲取

                  this.$store = typeof options.store === 'function'

                    ? options.store()

                    : options.store

                } else if (options.parent && options.parent.$store) { 

                // 如果options.store為空,則判斷options.parent.$store有沒有 從父元素判斷有沒有store,

                //從而保證子元素父元素公用一個store實例

                  this.$store = options.parent.$store

                }

              }

            }





            1.3 Vue.use(Vuex)總結

            至此,Vue.use(Vuex)全部分析完成,總結,就是Vue.use調用Vuex的install的方法,然后install使用mixin混入beforecreate生命周期中混入一個函數,當執(zhí)行生命周期beforecreate的時候回執(zhí)行vuexInit 。你可以慢慢調試,所以要好好利用下方的調試按鈕,第二個按鈕執(zhí)行下一步,第三個進入方法,兩個配合使用。





            2.new Vuex.Store

            Vue.use(Vuex)已經結束,再回到counter目錄下的store.js文件



            export default new Vuex.Store({

              state,

              getters,

              actions,

              mutations

            })





            debugger進入,Vuex.Store方法在src目錄下的store.js文件下



            export class Store {

              constructor (options = {}) {

              // 這里的options是在counter定義的 state,getters,actions,mutations當做參數傳進來

                // Auto install if it is not done yet and window has Vue.

                // To allow users to avoid auto-installation in some cases,

                // this code should be placed here. See #731

                if (!Vue && typeof window !== 'undefined' && window.Vue) {

                // 掛載在window上的自動安裝,也就是通過script標簽引入時不需要手動調用Vue.use(Vuex)

                  install(window.Vue)

                }



                if (process.env.NODE_ENV !== 'production') { 

                 // 開發(fā)環(huán)境 斷言,如果不符合條件 會警告,這里自行看

                  assert(Vue, must call Vue.use(Vuex) before creating a store instance.)

                  assert(typeof Promise !== 'undefined', vuex requires a Promise polyfill in this browser.)

                  assert(this instanceof Store, store must be called with the new operator.)

                }



                const {

                  plugins = [],

                  strict = false

                } = options



                // store internal state

                //下方是在Vuex的this上掛載一些對象,這里暫且不要知道他們要來干什么

                // 因為是源碼分析,不要所有的代碼都清除,第一次源碼分析,你就只當他們是掛載對象,往下看

                this._committing = false

                this._actions = Object.create(null)

                this._actionSubscribers = []

                this._mutations = Object.create(null)

                this._wrappedGetters = Object.create(null)

                // ModuleCollection代表模塊收集,形成模塊樹

                this._modules = new ModuleCollection(options) //碰到第一個不是定義空對象,debugger進去,分析在下面

                this._modulesNamespaceMap = Object.create(null)

                this._subscribers = []

                this._watcherVM = new Vue()

                this._makeLocalGettersCache = Object.create(null)



                // bind commit and dispatch to self

                const store = this

                const { dispatch, commit } = this

                this.dispatch = function boundDispatch (type, payload) { // 綁定dispatch的指針為store

                  return dispatch.call(store, type, payload)

                }

                this.commit = function boundCommit (type, payload, options) { // 綁定commit的指針為store

                  return commit.call(store, type, payload, options)

                }



                // strict mode

                this.strict = strict



                const state = this._modules.root.state // 獲取到用戶定義的state



                // init root module.

                // this also recursively registers all sub-modules

                // and collects all module getters inside this._wrappedGetters

                // 初始化root模塊 注冊getters,actions,mutations 子模塊

                installModule(this, state, [], this._modules.root)



                // initialize the store vm, which is responsible for the reactivity

                // (also registers _wrappedGetters as computed properties)

                // 初始化vm 用來監(jiān)聽state getter

                resetStoreVM(this, state)



                // apply plugins

                // 插件的注冊

                plugins.forEach(plugin => plugin(this))

            // 下方的是開發(fā)工具方面的 暫不提

                const useDevtools = options.devtools !== undefined ? options.devtools : Vue.config.devtools

                if (useDevtools) {

                  devtoolPlugin(this)

                }

              }

              }



            2.1 new ModuleCollection

            ModuleCollection函數在src目錄下的module目錄下的module-collection.js文件下



            export default class ModuleCollection {

              constructor (rawRootModule) { // rawRootModule === options

                // register root module (Vuex.Store options)

                this.register([], rawRootModule, false)

              }

            }



            2.1.1 register()



             register (path, rawModule, runtime = true) {

             // register([],options,false)

                if (process.env.NODE_ENV !== 'production') {

                  assertRawModule(path, rawModule) // 開發(fā)環(huán)境斷言,暫忽略

                }



                const newModule = new Module(rawModule, runtime)

                if (path.length === 0) { // path長度為0,為根節(jié)點,將newModule 賦值為root

                  this.root = newModule

                } else {

                  const parent = this.get(path.slice(0, -1))

                  parent.addChild(path[path.length - 1], newModule)

                }



                // register nested modules

                if (rawModule.modules) { // 如果存在子模塊,遞歸調用register,形成一棵樹

                  forEachValue(rawModule.modules, (rawChildModule, key) => {

                    this.register(path.concat(key), rawChildModule, runtime)

                  })

                }

              }

            1

            2

            3

            4

            5

            6

            7

            8

            9

            10

            11

            12

            13

            14

            15

            16

            17

            18

            19

            20

            21

            2.1.2 new Module()

            Module函數在同目錄下的modele.js文件下



            export default class Module {

            // new Module(options,false)

              constructor (rawModule, runtime) {

                this.runtime = runtime

                // Store some children item

                this._children = Object.create(null)

                // Store the origin module object which passed by programmer

                this._rawModule = rawModule // 將options放到Module上 用_raModele上

                const rawState = rawModule.state // 將你定義的state取出



                // Store the origin module's state

                // 如果你定義的state為函數,調用函數,為對象,則取對象 賦值為module上的state上

                this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}

              }

            }



            所以Module的this內容為如下:



            2.1.3 installModule



            function installModule (store, rootState, path, module, hot) {

            // installModule(Vuex,state,[],module) module是前面 new ModuleCollection產生的對象

              const isRoot = !path.length

              const namespace = store._modules.getNamespace(path)



              // register in namespace map

              if (module.namespaced) {

                if (store._modulesNamespaceMap[namespace] && process.env.NODE_ENV !== 'production') {

                  console.error([vuex] duplicate namespace ${namespace} for the namespaced module ${path.join('/')})

                }

                store._modulesNamespaceMap[namespace] = module

              }



              // set state

              if (!isRoot && !hot) {

                const parentState = getNestedState(rootState, path.slice(0, -1))

                const moduleName = path[path.length - 1]

                store._withCommit(() => {

                  if (process.env.NODE_ENV !== 'production') {

                    if (moduleName in parentState) {

                      console.warn(

                        [vuex] state field "${moduleName}" was overridden by a module with the same name at "${path.join('.')}"

                      )

                    }

                  }

                  Vue.set(parentState, moduleName, module.state)

                })

              }

            // 設置當前上下文

              const local = module.context = makeLocalContext(store, namespace, path)

            // 注冊mutation

              module.forEachMutation((mutation, key) => {

                const namespacedType = namespace + key

                registerMutation(store, namespacedType, mutation, local)

              })

            // 注冊action

              module.forEachAction((action, key) => {

                const type = action.root ? key : namespace + key

                const handler = action.handler || action

                registerAction(store, type, handler, local)

              })

            // 注冊getter

              module.forEachGetter((getter, key) => {

                const namespacedType = namespace + key

                registerGetter(store, namespacedType, getter, local)

              })

            // 逐一注冊子module

              module.forEachChild((child, key) => {

                installModule(store, rootState, path.concat(key), child, hot)

              })

            }



            2.1.4 makeLocalContext



            // 設置module的上下文,綁定對應的dispatch、commit、getters、state

            function makeLocalContext (store, namespace, path) {

              const noNamespace = namespace === ''



              const local = {

               //noNamespace 為true 使用原先的 至于后面的 不知道干啥用的 后面繼續(xù)研究

                dispatch: noNamespace ? store.dispatch : (_type, _payload, _options) => {

                  const args = unifyObjectStyle(_type, _payload, _options)

                  const { payload, options } = args

                  let { type } = args



                  if (!options || !options.root) {

                    type = namespace + type

                    if (process.env.NODE_ENV !== 'production' && !store._actions[type]) {

                      console.error([vuex] unknown local action type: ${args.type}, global type: ${type})

                      return

                    }

                  }



                  return store.dispatch(type, payload)

                },



                commit: noNamespace ? store.commit : (_type, _payload, _options) => {

                //noNamespace 為true 使用原先的

                  const args = unifyObjectStyle(_type, _payload, _options)

                  const { payload, options } = args

                  let { type } = args



                  if (!options || !options.root) {

                    type = namespace + type

                    if (process.env.NODE_ENV !== 'production' && !store._mutations[type]) {

                      console.error([vuex] unknown local mutation type: ${args.type}, global type: ${type})

                      return

                    }

                  }



                  store.commit(type, payload, options)

                }

              }



              // getters and state object must be gotten lazily

              // because they will be changed by vm update

              Object.defineProperties(local, {

                getters: {

                  get: noNamespace

                    ? () => store.getters

                    : () => makeLocalGetters(store, namespace)

                },

                state: {

                  get: () => getNestedState(store.state, path)

                }

              })



              return local

            }



            function getNestedState (state, path) {

              return path.reduce((state, key) => state[key], state)

            }

            2.1.5 registerMutation

            mutation的注冊,會調用下方方法,將wrappedMutationHandler函數放入到entry中



            function registerMutation(store, type, handler, local) {

             // entry和store._mutations[type] 指向同一個地址

              var entry = store._mutations[type] || (store._mutations[type] = []);

              entry.push(function wrappedMutationHandler(payload) {

                handler.call(store, local.state, payload);

              });

            }





            2.1.6 forEachAction

            action的注冊,會調用下方方法,將wrappedActionHandler函數放入到entry中



            function registerAction(store, type, handler, local) {

              var entry = store._actions[type] || (store._actions[type] = []);

               // entry和store._actions[type]指向同一個地址

              entry.push(function wrappedActionHandler(payload) {

                var res = handler.call(store, {

                  dispatch: local.dispatch,

                  commit: local.commit,

                  getters: local.getters,

                  state: local.state,

                  rootGetters: store.getters,

                  rootState: store.state

                }, payload);

                if (!(0, _util.isPromise)(res)) {

                  res = Promise.resolve(res);

                }

                if (store._devtoolHook) {

                  return res.catch(function (err) {

                    store._devtoolHook.emit('vuex:error', err);

                    throw err;

                  });

                } else {

                  return res;

                }

              });

            }



            因為entry和上面的_action[type],_mutations[type] 指向同一個地址,所以:



            2.1.7 forEachGetter

            getter的注冊,會調用下方方法



            function registerGetter(store, type, rawGetter, local) {

              if (store._wrappedGetters[type]) {

                if (true) {

                  console.error('[vuex] duplicate getter key: ' + type);

                }

                return;

              }

              store._wrappedGetters[type] = function wrappedGetter(store) {

                return rawGetter(local.state, // local state

                local.getters, // local getters

                store.state, // root state

                store.getters // root getters

                );

              };

            }







            2.1.8 resetStoreVM



            function resetStoreVM (store, state, hot) {

              const oldVm = store._vm //將_vm用變量保存



              // bind store public getters

              store.getters = {}

              // reset local getters cache

              store._makeLocalGettersCache = Object.create(null)

              const wrappedGetters = store._wrappedGetters // 獲取installModule方法完成的_wrappedGetters內容

              const computed = {}

              forEachValue(wrappedGetters, (fn, key) => {

                // use computed to leverage its lazy-caching mechanism

                // direct inline function use will lead to closure preserving oldVm.

                // using partial to return function with only arguments preserved in closure environment.

                computed[key] = partial(fn, store)

                Object.defineProperty(store.getters, key, {

                // 攔截get返回store._vm[key]中的值,即可以通過 this.$store.getters.xxx訪問值

                  get: () => store._vm[key],

                  enumerable: true // for local getters

                })

              })



              // use a Vue instance to store the state tree

              // suppress warnings just in case the user has added

              // some funky global mixins

              const silent = Vue.config.silent

              // silent設置為true,取消所有日志警告等

              Vue.config.silent = true

              store._vm = new Vue({ // 將state,getter的值進行監(jiān)聽,從這里就可以看出getter其實就是采用的vue的computed

                data: {

                  $$state: state

                },

                computed

              })

              // 恢復原先配置

              Vue.config.silent = silent



              // enable strict mode for new vm

              if (store.strict) {

                enableStrictMode(store)

              }

            // 若存在舊的實例,解除對state的引用,等dom更新后把舊的vue實例銷毀

              if (oldVm) {

                if (hot) {

                  // dispatch changes in all subscribed watchers

                  // to force getter re-evaluation for hot reloading.

                  store._withCommit(() => {

                    oldVm._data.$$state = null

                  })

                }

                Vue.nextTick(() => oldVm.$destroy())

              }

            }



            看到這里,你應該對vuex有初步的了解



             // 這也是我們?yōu)槭裁茨苡迷L問到state,getter的原因

             //this.store.dispatch('xxx') ,this.$store.dispatch('xxx')

            1

            2

            相信你也有點亂,其實上面很多我沒講到的不是我不想講,是具體我也不知道干啥的,看源碼學習呢,看主要就行,后面理解多了,其他的就慢慢都會,你不可能剛開始看,就每一行,他寫的每一句的用途都知道是干什么的,只能先看主要方法,在慢慢琢磨,一步步來吧,別急,現在我來畫一個流程圖,更好的去理解吧。

            2.1.9 流程圖





            3.連貫

            import Vue from 'vue'

            import Counter from './Counter.vue'

            import store from './store'



            new Vue({

              el: '#app',

              store,

              render: h => h(Counter)

            })



            當運行new Vue的時候,傳入了store,前面minix beforecreate,執(zhí)行到beforecreate鉤子時,會調用vueInit函數,就可以在this.$store取到store對象了,因為options.store有值了 ,不為空,這樣就連貫到了,所以這就是為什么可以用this.$store取值。


            日歷

            鏈接

            個人資料

            藍藍設計的小編 http://www.dzxscac.cn

            存檔

            主站蜘蛛池模板: www.欧美激情| 国产精品青青在线麻豆| 欧美69久成人做爰视频| 大乳丰满人妻中文字幕日本| 亚洲中文字幕永久在线全国| 黄色成人在线| 三级成人| 国产极品视觉盛宴| 亚洲欧美中文日韩v在线观看不卡| 美女黄色真播| 日韩激情无码免费毛片| 国精品无码一区二区三区在线a片| 爱操影院| 日韩淫片毛片视频免费看| 亚洲国产精品线久久| 日韩性生活视频| www.男人的天堂.com| 欧美人与禽zoz0性伦交| 久久精品女同亚洲女同| 丁香花五月| 毛片久久网站小视频| 国产免费不卡av在线播放| 国产美女免费| 日韩一区二区三区中文字幕| 丰满爆乳在线播放| 欧美性xxxx| 日本a级片网站| 一本无码久本草在线中文字幕dvd 加勒比无码一区二区三区 | 中文字幕av影院| 久久亚洲精品中文字幕无男同| 国产又色又爽无遮挡免费软件| 五月婷婷中文| 欧美老熟妇一区二区三区| 被灌满精子的少妇视频| 男女做爰猛烈啪啪吃奶动| 成年人黄色小视频| 青青草国产精品一区二区| 又大又粗又黄的网站不卡无码| 男女涩涩视频| 日韩激情文学| 在线播放无码字幕亚洲|