<font id="zqva1"></font>
<rt id="zqva1"></rt>
  • <tt id="zqva1"></tt>
    <cite id="zqva1"></cite>

    <cite id="zqva1"><noscript id="zqva1"></noscript></cite>
      <rp id="zqva1"><meter id="zqva1"></meter></rp>

        <cite id="zqva1"></cite>
          <b id="zqva1"></b>
          <rp id="zqva1"></rp>
          <cite id="zqva1"></cite>

          <rt id="zqva1"></rt>

        1. <rp id="zqva1"></rp>

          Vue.js學習,關于Vuex源碼解析

          時間:?2017-12-18閱讀:?939標簽:?vuex

          Vuex

          我們在使用Vue.js開發復雜的應用時,經常會遇到多個組件共享同一個狀態,亦或是多個組件會去更新同一個狀態,在應用代碼量較少的時候,我們可以組件間通信去維護修改數據,或者是通過事件總線來進行數據的傳遞以及修改。但是當應用逐漸龐大以后,代碼就會變得難以維護,從父組件開始通過prop傳遞多層嵌套的數據由于層級過深而顯得異常脆弱,而事件總線也會因為組件的增多、代碼量的增大而顯得交互錯綜復雜,難以捋清其中的傳遞關系。

          那么為什么我們不能將數據層與組件層抽離開來呢?把數據層放到全局形成一個單一的Store,組件層變得更薄,專門用來進行數據的展示及操作。所有數據的變更都需要經過全局的Store來進行,形成一個單向數據流,使數據變化變得“可預測”。

          Vuex是一個專門為Vue.js框架設計的、用于對Vue.js應用程序進行狀態管理的庫,它借鑒了Flux、redux的基本思想,將共享的數據抽離到全局,以一個單例存放,同時利用Vue.js的響應式機制來進行高效的狀態管理與更新。正是因為Vuex使用了Vue.js內部的“響應式機制”,所以Vuex是一個專門為Vue.js設計并與之高度契合的框架(優點是更加簡潔高效,缺點是只能跟Vue.js搭配使用)。具體使用方法及API可以參考Vuex的官網

          先來看一下這張Vuex的數據流程圖,熟悉Vuex使用的同學應該已經有所了解。


          Vuex實現了一個單向數據流,在全局擁有一個State存放數據,所有修改State的操作必須通過Mutation進行,Mutation的同時提供了訂閱者模式供外部插件調用獲取State數據的更新。所有異步接口需要走Action,常見于調用后端接口異步獲取更新數據,而Action也是無法直接修改State的,還是需要通過Mutation來修改State的數據。最后,根據State的變化,渲染到視圖上。Vuex運行依賴Vue內部數據雙向綁定機制,需要new一個Vue對象來實現“響應式化”,所以Vuex是一個專門為Vue.js設計的狀態管理庫。


          安裝

          使用過Vuex的朋友一定知道,Vuex的安裝十分簡單,只需要提供一個store,然后執行下面兩句代碼即完成的Vuex的引入。

          Vue.use(Vuex);
          
          /*將store放入Vue創建時的option中*/
          new Vue({
              el: '#app',
              store
          });

          那么問題來了,Vuex是怎樣把store注入到Vue實例中去的呢?

          Vue.js提供了Vue.use方法用來給Vue.js安裝插件,內部通過調用插件的install方法(當插件是一個對象的時候)來進行插件的安裝。

          我們來看一下Vuex的install實現。

          /*暴露給外部的插件install方法,供Vue.use調用安裝插件*/
          export function install (_Vue) {
            if (Vue) {
              /*避免重復安裝(Vue.use內部也會檢測一次是否重復安裝同一個插件)*/
              if (process.env.NODE_ENV !== 'production') {
                console.error(
                  '[vuex] already installed. Vue.use(Vuex) should be called only once.'
                )
              }
              return
            }
            /*保存Vue,同時用于檢測是否重復安裝*/
            Vue = _Vue
            /*將vuexInit混淆進Vue的beforeCreate(Vue2.0)或_init方法(Vue1.0)*/
            applyMixin(Vue)
          }

          這段install代碼做了兩件事情,一件是防止Vuex被重復安裝,另一件是執行applyMixin,目的是執行vuexInit方法初始化Vuex。Vuex針對Vue1.0與2.0分別進行了不同的處理,如果是Vue1.0,Vuex會將vuexInit方法放入Vue的_init方法中,而對于Vue2.0,則會將vuexinit混淆進Vue的beforeCreacte鉤子中。來看一下vuexInit的代碼。

           /*Vuex的init鉤子,會存入每一個Vue實例等鉤子列表*/
            function vuexInit () {
              const options = this.$options
              // store injection
              if (options.store) {
                /*存在store其實代表的就是Root節點,直接執行store(function時)或者使用store(非function)*/
                this.$store = typeof options.store === 'function'
                  ? options.store()
                  : options.store
              } else if (options.parent && options.parent.$store) {
                /*子組件直接從父組件中獲取$store,這樣就保證了所有組件都公用了全局的同一份store*/
                this.$store = options.parent.$store
              }
            }

          vuexInit會嘗試從options中獲取store,如果當前組件是根組件(Root節點),則options中會存在store,直接獲取賦值給$store即可。如果當前組件非根組件,則通過options中的parent獲取父組件的$store引用。這樣一來,所有的組件都獲取到了同一份內存地址的Store實例,于是我們可以在每一個組件中通過this.$store愉快地訪問全局的Store實例了。

          那么,什么是Store實例?


          Store

          我們傳入到根組件到store,就是Store實例,用Vuex提供到Store方法構造。

          export default new Vuex.Store({
              strict: true,
              modules: {
                  moduleA,
                  moduleB
              }
          });

          我們來看一下Store的實現。首先是構造函數。

          constructor (options = {}) {
              // 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
              /*
                在瀏覽器環境下,如果插件還未安裝(!Vue即判斷是否未安裝),則它會自動安裝。
                它允許用戶在某些情況下避免自動安裝。
              */
              if (!Vue && typeof window !== 'undefined' && window.Vue) {
                install(window.Vue)
              }
          
              if (process.env.NODE_ENV !== 'production') {
                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 {
                /*一個數組,包含應用在 store 上的插件方法。這些插件直接接收 store 作為唯一參數,可以監聽 mutation(用于外部地數據持久化、記錄或調試)或者提交 mutation (用于內部數據,例如 websocket 或 某些觀察者)*/
                plugins = [],
                /*使 Vuex store 進入嚴格模式,在嚴格模式下,任何 mutation 處理函數以外修改 Vuex state 都會拋出錯誤。*/
                strict = false
              } = options
          
              /*從option中取出state,如果state是function則執行,最終得到一個對象*/
              let {
                state = {}
              } = options
              if (typeof state === 'function') {
                state = state()
              }
          
              // store internal state
              /* 用來判斷嚴格模式下是否是用mutation修改state的 */
              this._committing = false
              /* 存放action */
              this._actions = Object.create(null)
              /* 存放mutation */
              this._mutations = Object.create(null)
              /* 存放getter */
              this._wrappedGetters = Object.create(null)
              /* module收集器 */
              this._modules = new ModuleCollection(options)
              /* 根據namespace存放module */
              this._modulesNamespaceMap = Object.create(null)
              /* 存放訂閱者 */
              this._subscribers = []
              /* 用以實現Watch的Vue實例 */
              this._watcherVM = new Vue()
          
              // bind commit and dispatch to self
              /*將dispatch與commit調用的this綁定為store對象本身,否則在組件內部this.dispatch時的this會指向組件的vm*/
              const store = this
              const { dispatch, commit } = this
              /* 為dispatch與commit綁定this(Store實例本身) */
              this.dispatch = function boundDispatch (type, payload) {
                return dispatch.call(store, type, payload)
              }
              this.commit = function boundCommit (type, payload, options) {
                return commit.call(store, type, payload, options)
              }
          
              // strict mode
              /*嚴格模式(使 Vuex store 進入嚴格模式,在嚴格模式下,任何 mutation 處理函數以外修改 Vuex state 都會拋出錯誤)*/
              this.strict = strict
          
              // init root module.
              // this also recursively registers all sub-modules
              // and collects all module getters inside this._wrappedGetters
              /*初始化根module,這也同時遞歸注冊了所有子modle,收集所有module的getter到_wrappedGetters中去,this._modules.root代表根module才獨有保存的Module對象*/
              installModule(this, state, [], this._modules.root)
          
              // initialize the store vm, which is responsible for the reactivity
              // (also registers _wrappedGetters as computed properties)
              /* 通過vm重設store,新建Vue對象使用Vue內部的響應式實現注冊state以及computed */
              resetStoreVM(this, state)
          
              // apply plugins
              /* 調用插件 */
              plugins.forEach(plugin => plugin(this))
          
              /* devtool插件 */
              if (Vue.config.devtools) {
                devtoolPlugin(this)
              }
            }

          Store的構造類除了初始化一些內部變量以外,主要執行了installModule(初始化module)以及resetStoreVM(通過VM使store“響應式”)。


          installModule

          installModule的作用主要是用為module加上namespace名字空間(如果有)后,注冊mutation、action以及getter,同時遞歸安裝所有子module。

          /*初始化module*/
          function installModule (store, rootState, path, module, hot) {
            /* 是否是根module */
            const isRoot = !path.length
            /* 獲取module的namespace */
            const namespace = store._modules.getNamespace(path)
          
            // register in namespace map
            /* 如果有namespace則在_modulesNamespaceMap中注冊 */
            if (module.namespaced) {
              store._modulesNamespaceMap[namespace] = module
            }
          
            // set state
            if (!isRoot && !hot) {
              /* 獲取父級的state */
              const parentState = getNestedState(rootState, path.slice(0, -1))
              /* module的name */
              const moduleName = path[path.length - 1]
              store.`_withCommit`(() => {
                /* 將子module設置稱響應式的 */
                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 namespacedType = namespace + key
              registerAction(store, namespacedType, action, local)
            })
          
            /* 遍歷注冊getter */
            module.forEachGetter((getter, key) => {
              const namespacedType = namespace + key
              registerGetter(store, namespacedType, getter, local)
            })
          
            /* 遞歸安裝mudule */
            module.forEachChild((child, key) => {
              installModule(store, rootState, path.concat(key), child, hot)
            })
          }


          resetStoreVM

          在說resetStoreVM之前,先來看一個小demo。

          let globalData = {
              d: 'hello world'
          };
          new Vue({
              data () {
                  return {
                      $$state: {
                          globalData
                      }
                  }
              }
          });
          
          /* modify */
          setTimeout(() => {
              globalData.d = 'hi~';
          }, 1000);
          
          Vue.prototype.globalData = globalData;
          
          /* 任意模板中 */
          <div>{{globalData.d}}</div>

          上述代碼在全局有一個globalData,它被傳入一個Vue對象的data中,之后在任意Vue模板中對該變量進行展示,因為此時globalData已經在Vue的prototype上了所以直接通過this.prototype訪問,也就是在模板中的{{prototype.d}}。此時,setTimeout在1s之后將globalData.d進行修改,我們發現模板中的globalData.d發生了變化。其實上述部分就是Vuex依賴Vue核心實現數據的“響應式化”。

          不熟悉Vue.js響應式原理的同學可以通過筆者另一篇文章響應式原理了解Vue.js是如何進行數據雙向綁定的。

          接著來看代碼。

          /* 通過vm重設store,新建Vue對象使用Vue內部的響應式實現注冊state以及computed */
          function resetStoreVM (store, state, hot) {
            /* 存放之前的vm對象 */
            const oldVm = store._vm 
          
            // bind store public getters
            store.getters = {}
            const wrappedGetters = store._wrappedGetters
            const computed = {}
          
            /* 通過Object.defineProperty為每一個getter方法設置get方法,比如獲取this.$store.getters.test的時候獲取的是store._vm.test,也就是Vue對象的computed屬性 */
            forEachValue(wrappedGetters, (fn, key) => {
              // use computed to leverage its lazy-caching mechanism
              computed[key] = () => fn(store)
              Object.defineProperty(store.getters, key, {
                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
            /* Vue.config.silent暫時設置為true的目的是在new一個Vue實例的過程中不會報出一切警告 */
            Vue.config.silent = true
            /*  這里new了一個Vue對象,運用Vue內部的響應式實現注冊state以及computed*/
            store._vm = new Vue({
              data: {
                $$state: state
              },
              computed
            })
            Vue.config.silent = silent
          
            // enable strict mode for new vm
            /* 使能嚴格模式,保證修改store只能通過mutation */
            if (store.strict) {
              enableStrictMode(store)
            }
          
            if (oldVm) {
              /* 解除舊vm的state的引用,以及銷毀舊的Vue對象 */
              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())
            }
          }

          resetStoreVM首先會遍歷wrappedGetters,使用Object.defineProperty方法為每一個getter綁定上get方法,這樣我們就可以在組件里訪問this.$store.getter.test就等同于訪問store._vm.test。

          forEachValue(wrappedGetters, (fn, key) => {
            // use computed to leverage its lazy-caching mechanism
            computed[key] = () => fn(store)
            Object.defineProperty(store.getters, key, {
              get: () => store._vm[key],
              enumerable: true // for local getters
            })
          })

          之后Vuex采用了new一個Vue對象來實現數據的“響應式化”,運用Vue.js內部提供的數據雙向綁定功能來實現store的數據與視圖的同步更新。

          store._vm = new Vue({
            data: {
              $$state: state
            },
            computed
          })

          這時候我們訪問store._vm.test也就訪問了Vue實例中的屬性。

          這兩步執行完以后,我們就可以通過this.$store.getter.test訪問vm中的test屬性了。


          嚴格模式

          Vuex的Store構造類的option有一個strict的參數,可以控制Vuex執行嚴格模式,嚴格模式下,所有修改state的操作必須通過mutation實現,否則會拋出錯誤。

          /* 使能嚴格模式 */
          function enableStrictMode (store) {
            store._vm.$watch(function () { return this._data.$$state }, () => {
              if (process.env.NODE_ENV !== 'production') {
                /* 檢測store中的_committing的值,如果是true代表不是通過mutation的方法修改的 */
                assert(store._committing, `Do not mutate vuex store state outside mutation handlers.`)
              }
            }, { deep: true, sync: true })
          }

          首先,在嚴格模式下,Vuex會利用vm的$watch方法來觀察$$state,也就是Store的state,在它被修改的時候進入回調。我們發現,回調中只有一句話,用assert斷言來檢測store._committing,當store._committing為false的時候會觸發斷言,拋出異常。

          我們發現,Store的commit方法中,執行mutation的語句是這樣的。

          this._withCommit(() => {
            entry.forEach(function commitIterator (handler) {
              handler(payload)
            })
          })

          再來看看_withCommit的實現。

          _withCommit (fn) {
            /* 調用withCommit修改state的值時會將store的committing值置為true,內部會有斷言檢查該值,在嚴格模式下只允許使用mutation來修改store中的值,而不允許直接修改store的數值 */
            const committing = this._committing
            this._committing = true
            fn()
            this._committing = committing
          }

          我們發現,通過commit(mutation)修改state數據的時候,會再調用mutation方法之前將committing置為true,接下來再通過mutation函數修改state中的數據,這時候觸發$watch中的回調斷言committing是不會拋出異常的(此時committing為true)。而當我們直接修改state的數據時,觸發$watch的回調執行斷言,這時committing為false,則會拋出異常。這就是Vuex的嚴格模式的實現。

          接下來我們來看看Store提供的一些API。


          commit(mutation

          /* 調用mutation的commit方法 */
          commit (_type, _payload, _options) {
            // check object-style commit
            /* 校驗參數 */
            const {
              type,
              payload,
              options
            } = unifyObjectStyle(_type, _payload, _options)
          
            const mutation = { type, payload }
            /* 取出type對應的mutation的方法 */
            const entry = this._mutations[type]
            if (!entry) {
              if (process.env.NODE_ENV !== 'production') {
                console.error(`[vuex] unknown mutation type: ${type}`)
              }
              return
            }
            /* 執行mutation中的所有方法 */
            this._withCommit(() => {
              entry.forEach(function commitIterator (handler) {
                handler(payload)
              })
            })
            /* 通知所有訂閱者 */
            this._subscribers.forEach(sub => sub(mutation, this.state))
          
            if (
              process.env.NODE_ENV !== 'production' &&
              options && options.silent
            ) {
              console.warn(
                `[vuex] mutation type: ${type}. Silent option has been removed. ` +
                'Use the filter functionality in the vue-devtools'
              )
            }
          }

          commit方法會根據type找到并調用_mutations中的所有type對應的mutation方法,所以當沒有namespace的時候,commit方法會觸發所有module中的mutation方法。再執行完所有的mutation之后會執行_subscribers中的所有訂閱者。我們來看一下_subscribers是什么。

          Store給外部提供了一個subscribe方法,用以注冊一個訂閱函數,會push到Store實例的_subscribers中,同時返回一個從_subscribers中注銷該訂閱者的方法。

          /* 注冊一個訂閱函數,返回取消訂閱的函數 */
          subscribe (fn) {
            const subs = this._subscribers
            if (subs.indexOf(fn) < 0) {
              subs.push(fn)
            }
            return () => {
              const i = subs.indexOf(fn)
              if (i > -1) {
                subs.splice(i, 1)
              }
            }
          }

          在commit結束以后則會調用這些_subscribers中的訂閱者,這個訂閱者模式提供給外部一個監視state變化的可能。state通過mutation改變時,可以有效補獲這些變化。


          dispatch(action

          來看一下dispatch的實現。

          /* 調用action的dispatch方法 */
          dispatch (_type, _payload) {
            // check object-style dispatch
            const {
              type,
              payload
            } = unifyObjectStyle(_type, _payload)
          
            /* actions中取出type對應的ation */
            const entry = this._actions[type]
            if (!entry) {
              if (process.env.NODE_ENV !== 'production') {
                console.error(`[vuex] unknown action type: ${type}`)
              }
              return
            }
          
            /* 是數組則包裝Promise形成一個新的Promise,只有一個則直接返回第0個 */
            return entry.length > 1
              ? Promise.all(entry.map(handler => handler(payload)))
              : entry[0](payload)
          }

          以及registerAction時候做的事情。

          /* 遍歷注冊action */
          function registerAction (store, type, handler, local) {
            /* 取出type對應的action */
            const entry = store._actions[type] || (store._actions[type] = [])
            entry.push(function wrappedActionHandler (payload, cb) {
              let res = handler.call(store, {
                dispatch: local.dispatch,
                commit: local.commit,
                getters: local.getters,
                state: local.state,
                rootGetters: store.getters,
                rootState: store.state
              }, payload, cb)
              /* 判斷是否是Promise */
              if (!isPromise(res)) {
                /* 不是Promise對象的時候轉化稱Promise對象 */
                res = Promise.resolve(res)
              }
              if (store._devtoolHook) {
                /* 存在devtool插件的時候觸發vuex的error給devtool */
                return res.catch(err => {
                  store._devtoolHook.emit('vuex:error', err)
                  throw err
                })
              } else {
                return res
              }
            })
          }

          因為registerAction的時候將push進_actions的action進行了一層封裝(wrappedActionHandler),所以我們在進行dispatch的第一個參數中獲取state、commit等方法。之后,執行結果res會被進行判斷是否是Promise,不是則會進行一層封裝,將其轉化成Promise對象。dispatch時則從_actions中取出,只有一個的時候直接返回,否則用Promise.all處理再返回。


          watch

          /* 觀察一個getter方法 */
          watch (getter, cb, options) {
            if (process.env.NODE_ENV !== 'production') {
              assert(typeof getter === 'function', `store.watch only accepts a function.`)
            }
            return this._watcherVM.$watch(() => getter(this.state, this.getters), cb, options)
          }

          熟悉Vue的朋友應該很熟悉watch這個方法。這里采用了比較巧妙的設計,_watcherVM是一個Vue的實例,所以watch就可以直接采用了Vue內部的watch特性提供了一種觀察數據getter變動的方法。


          registerModule

          /* 注冊一個動態module,當業務進行異步加載的時候,可以通過該接口進行注冊動態module */
          registerModule (path, rawModule) {
            /* 轉化稱Array */
            if (typeof path === 'string') path = [path]
          
            if (process.env.NODE_ENV !== 'production') {
              assert(Array.isArray(path), `module path must be a string or an Array.`)
              assert(path.length > 0, 'cannot register the root module by using registerModule.')
            }
          
            /*注冊*/
            this._modules.register(path, rawModule)
            /*初始化module*/
            installModule(this, this.state, path, this._modules.get(path))
            // reset store to update getters...
            /* 通過vm重設store,新建Vue對象使用Vue內部的響應式實現注冊state以及computed */
            resetStoreVM(this, this.state)
          }

          registerModule用以注冊一個動態模塊,也就是在store創建以后再注冊模塊的時候用該接口。內部實現實際上也只有installModule與resetStoreVM兩個步驟,前面已經講過,這里不再累述。


          unregisterModule

           /* 注銷一個動態module */
          unregisterModule (path) {
            /* 轉化稱Array */
            if (typeof path === 'string') path = [path]
          
            if (process.env.NODE_ENV !== 'production') {
              assert(Array.isArray(path), `module path must be a string or an Array.`)
            }
          
            /*注銷*/
            this._modules.unregister(path)
            this._withCommit(() => {
              /* 獲取父級的state */
              const parentState = getNestedState(this.state, path.slice(0, -1))
              /* 從父級中刪除 */
              Vue.delete(parentState, path[path.length - 1])
            })
            /* 重制store */
            resetStore(this)
          }

          同樣,與registerModule對應的方法unregisterModule,動態注銷模塊。實現方法是先從state中刪除模塊,然后用resetStore來重制store。


          resetStore

          /* 重制store */
          function resetStore (store, hot) {
            store._actions = Object.create(null)
            store._mutations = Object.create(null)
            store._wrappedGetters = Object.create(null)
            store._modulesNamespaceMap = Object.create(null)
            const state = store.state
            // init all modules
            installModule(store, state, [], store._modules.root, true)
            // reset vm
            resetStoreVM(store, state, hot)
          }

          這里的resetStore其實也就是將store中的_actions等進行初始化以后,重新執行installModule與resetStoreVM來初始化module以及用Vue特性使其“響應式化”,這跟構造函數中的是一致的。


          插件

          Vue提供了一個非常好用的插件Vue.js devtools

          /* 從window對象的__VUE_DEVTOOLS_GLOBAL_HOOK__中獲取devtool插件 */
          const devtoolHook =
            typeof window !== 'undefined' &&
            window.__VUE_DEVTOOLS_GLOBAL_HOOK__
          
          export default function devtoolPlugin (store) {
            if (!devtoolHook) return
          
            /* devtoll插件實例存儲在store的_devtoolHook上 */
            store._devtoolHook = devtoolHook
          
            /* 出發vuex的初始化事件,并將store的引用地址傳給deltool插件,使插件獲取store的實例 */
            devtoolHook.emit('vuex:init', store)
          
            /* 監聽travel-to-state事件 */
            devtoolHook.on('vuex:travel-to-state', targetState => {
              /* 重制state */
              store.replaceState(targetState)
            })
          
            /* 訂閱store的變化 */
            store.subscribe((mutation, state) => {
              devtoolHook.emit('vuex:mutation', mutation, state)
            })
          }

          如果已經安裝了該插件,則會在windows對象上暴露一個__VUE_DEVTOOLS_GLOBAL_HOOK__。devtoolHook用在初始化的時候會觸發“vuex:init”事件通知插件,然后通過on方法監聽“vuex:travel-to-state”事件來重置state。最后通過Store的subscribe方法來添加一個訂閱者,在觸發commit方法修改mutation數據以后,該訂閱者會被通知,從而觸發“vuex:mutation”事件。


          最后

          Vuex是一個非常優秀的庫,代碼量不多且結構清晰,非常適合研究學習其內部實現。最近的一系列源碼閱讀也使我自己受益匪淺,寫這篇文章也希望可以幫助到更多想要學習探索Vuex內部實現原理的同學。


          來源:https://github.com/answershuto/learnVue/blob/master/docs/Vuex%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90.MarkDown

          站長推薦

          1.阿里云: 本站目前使用的是阿里云主機,安全/可靠/穩定。點擊領取2000元代金券、了解最新阿里云產品的各種優惠活動點擊進入

          2.騰訊云: 提供云服務器、云數據庫、云存儲、視頻與CDN、域名等服務。騰訊云各類產品的最新活動,優惠券領取點擊進入

          3.廣告聯盟: 整理了目前主流的廣告聯盟平臺,如果你有流量,可以作為參考選擇適合你的平臺點擊進入

          鏈接: http://www.modern-decoration.com.cn/article/detial/253

          Vuex的數據重新加載頁面后消失

          一般我們在登錄成功的時候需要把用戶信息,菜單信息放置vuex中,作為全局的共享數據。但是在頁面刷新的時候vuex里的數據會重新初始化,導致數據丟失。因為vuex里的數據是保存在運行內存中的,當頁面刷新時,頁面會重新加載vue實例

          vuex的持久化

          Vuex是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應 用的所有組件的狀態,并以相應的規則保證狀態以一種可預測的方式發生變化.

          結合 Vue.observable 寫一個簡易 Vuex

          作為 Vue 全家桶的一員,Vuex 的重要性不言而喻,不管是用來管理狀態,還是封裝 Controler 都很好用。不過在一些體量較小的項目中,為了幾個簡單的狀態或者處理函數而引入 Vuex,就像是高射炮打蚊子,大材小用了

          頁面刷新時vuex數據持久化問題的解決方案

          vuex是在中大型項目中必不可少的狀態管理組件,刷新會重新更新狀態,但是有時候我們并不希望如此。例如全局相關的,如登錄狀態、token、以及一些不常更新的狀態等,我們更希望能夠固化到本地,減少無用的接口訪問,以及更佳的用戶體驗。

          Vuex與組件通信

          Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。也就是說 Vuex 用于單頁面應用組件之間的數據共享,在組件嵌套很多層的情況下,Vue 中父子組件的通信過程就變得很麻煩,此時使用 Vuex 方便了組件間的通信。

          vue中 Vuex

          由于狀態零散地分布在許多組件和組件之間的交互中,大型應用復雜度也經常逐漸增長。為了解決這個問題,Vue 提供 vuex。Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態

          如何簡化你的Vuex Store

          隨著Vue應用程序的大小增加,Vuex Store中的actions和mutations也會增加。本文,我們將介紹如何將其減少到易于管理的東西。Vuex是vue.js應用程序的狀態管理模式+庫。它充當應用程序中所有組件的集中存儲

          Vuex新手的理解與使用

          開始嘗試學習使用vue,是因為此前總是遇到頁面邏輯數據與視圖的一致性問題.在使用vue之前,我們使用jQuery插件的時候,一樁麻煩事就是既要在每個數據變更后,寫代碼去改變視圖,又要考慮html上各種輸入

          Vuex狀態管理,state、getter

          首先在 vue 2.0+ 你的vue-cli項目中安裝 vuex :然后 在src文件目錄下新建一個名為store的文件夾,為方便引入并在store文件夾里新建一個index.js,里面的內容如下:接下來,在 main.js里面引入store,然后再全局注入一下

          vue單頁面應用刷新網頁后vuex的state數據丟失的解決方案

          其實很簡單,因為store里的數據是保存在運行內存中的,當頁面刷新時,頁面會重新加載vue實例,store里面的數據就會被重新賦值。一種是state里的數據全部是通過請求來觸發action或mutation來改變

          fly63.com版權所有,內容以共享、參考、研究為目的,不存在任何商業目的。其版權屬原作者所有,如有侵權,請與小編聯系!情況屬實本人將予以刪除!

          文章投稿關于web前端網站點搜索站長推薦網站地圖站長QQ:522607023

          小程序專欄: 土味情話心理測試腦筋急轉彎幽默笑話段子句子語錄成語大全運營推廣

          国产精品高清视频免费 - 视频 - 在线观看 - 影视资讯 - 唯爱网