日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > vue >内容正文

vue

Vue组件通信原理剖析(二)全局状态管理Vuex

發(fā)布時間:2023/12/10 vue 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Vue组件通信原理剖析(二)全局状态管理Vuex 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

首先我們先從一個面試題入手。

面試官問: “Vue中組件通信的常用方式有哪些?”
我答:
1. props
2. 自定義事件
3. eventbus
4. vuex
5. 還有常見的邊界情況$parent、$children、$root、$refs、provide/inject
6. 此外還有一些非props特性$attrs、$listeners

面試官追問:“那你能分別說說他們的原理嗎?”
我:[一臉懵逼]😳

今天我們來看看Vuex內(nèi)部的奧秘!
如果要看別的屬性原理請移步到Vue組件通信原理剖析(一)事件總線的基石 on和on和onemit和Vue組件通信原理剖析(三)provide/inject原理分析

vuex

Vuex集中式存儲管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以可預(yù)測的方式發(fā)生變化。

我們先看看如何使用vuex,

  • 第一步:定義一個Store

    // store/index.js import Vue from 'vue' import Vuex from 'vuex'Vue.use(Vuex)export default = new Vuex.Store({state: {counter: 0},getters: {doubleCounter(state) {return state.counter * 2}},mutations: {add(state) {state.counter ++ }},actions: {add({commit}) {setTimeout(() => {commit('add')}, 1000);}} })
  • 第二步,掛載app

    // main.js import vue from 'vue' import App form './App.vue' import store from './store'new Vue({store,render: h => h(App) }).$mount('#app')
  • 第三步:狀態(tài)調(diào)用

    // test.vue <p @click="$store.commit('add')">counter: {{ $store.state.counter }}</p> <p @click="$store.dispatch('add')">async counter: {{ $store.state.counter }}</p> <p>double counter: {{ $store.getters.doubleCounter }}</p>

從上面的例子,我們可以看出,vuex需要具備這么幾個特點:

  • 使用Vuex只需執(zhí)行 Vue.use(Vuex),保證vuex是以插件的形式被vue加載。
  • state的數(shù)據(jù)具有響應(yīng)式,A組件中修改了,B組件中可用修改后的值。
  • getters可以對state的數(shù)據(jù)做動態(tài)派生。
  • mutations中的方法是同步修改。
  • actions中的方法是異步修改。
  • 那我們今天就去源碼里探索以下,vuex是怎么實現(xiàn)的,又是怎么解決以上的問題的!

    問題1:vuex的插件加載機制

    所謂插件機制,就是需要實現(xiàn)Install方法,并且通過mixin形式混入到Vue的生命周期中,我們先來看看Vuex的定義

    • 需要對外暴露一個對象,這樣就可以滿足new Vuex.Store()

      // src/index.js import { Store, install } from './store' import { mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers } from './helpers'export default {Store,install,version: '__VERSION__',mapState,mapMutations,mapGetters,mapActions,createNamespacedHelpers }
    • 其次是定義store,并且實現(xiàn)vue的Install方法

      // src/store.js let Vue // bind on installexport class Store {...... }// 實現(xiàn)的Install方法 export function install (_Vue) {if (Vue && _Vue === Vue) {if (process.env.NODE_ENV !== 'production') {console.error('[vuex] already installed. Vue.use(Vuex) should be called only once.')}return}Vue = _VueapplyMixin(Vue) }

    問題2:state的數(shù)據(jù)響應(yīng)式

    看懂了Vuex的入口定義,下面我們就針對store的定義來一探究竟,先看看state的實現(xiàn)

    // src/store.js export class Store {constructor(options = {}) {......// strict modethis.strict = strictconst state = this._modules.root.state// initialize the store vm, which is responsible for the reactivity// (also registers _wrappedGetters as computed properties)// 看上面的注釋可以得知,resetStoreVM就是初始化store中負(fù)責(zé)響應(yīng)式的vm的方法,而且還注冊所有的gettersz作為vm的計算屬性resetStoreVM(this, state)} }

    我們來看看resetStoreVM的具體實現(xiàn)

    // src/store.js function resetStoreVM (store, state, hot) {const oldVm = store._vm// bind store public gettersstore.getters = {}// reset local getters cachestore._makeLocalGettersCache = Object.create(null)const wrappedGetters = store._wrappedGettersconst computed = {}// 這里是實現(xiàn)getters的派生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],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// 這是是通過new一個Vue實例,并將state作為實例的datas屬性,那他自然而然就具有了響應(yīng)式const silent = Vue.config.silentVue.config.silent = truestore._vm = new Vue({data: {$$state: state},computed})Vue.config.silent = silent// enable strict mode for new vmif (store.strict) {enableStrictMode(store)}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())} }

    問題3:getters實現(xiàn)state中的數(shù)據(jù)的派生

    關(guān)于getters的實現(xiàn),我們在上面也做了相應(yīng)的解釋,實際上就是將getters的方法包裝一層后,收集到computed對象中,并使用Object.defineProperty注冊store.getters,使得每次取值時,從store._vm中取。

    關(guān)鍵的步驟就是創(chuàng)建一個Vue的實例

    store._vm = new Vue({data: {$$state: state // 這是store中的所有state},computed // 這是store中的所有g(shù)etters })

    問題4:mutations中同步commit

    // src/store.js // store的構(gòu)造函數(shù) constructor(options = {}) {// 首先在構(gòu)造方法中,把store中的commit和dispatch綁定到自己的實例上,// 為什么要這么做呢?// 是因為在commit或者dispatch時,尤其是dispatch,執(zhí)行function時會調(diào)用實例this,而方法體內(nèi)的this是具有作用域?qū)傩缘?#xff0c;所以如果要保證每次this都代表store實例,就需要重新綁定一下。const store = thisconst { dispatch, commit } = thisthis.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)} }// commit 的實現(xiàn) commit (_type, _payload, _options) {// check object-style commitconst {type,payload,options} = unifyObjectStyle(_type, _payload, _options)const mutation = { type, payload }// 通過傳入的類型,查找到mutations中的對應(yīng)的入口函數(shù)const entry = this._mutations[type]......// 這里是執(zhí)行的主方法,通過遍歷入口函數(shù),并傳參執(zhí)行this._withCommit(() => {entry.forEach(function commitIterator (handler) {handler(payload)})})...... }

    問題5:actions中的異步dispatch

    上面說了在構(gòu)造store時綁定dispatch的原因,下面我們就繼續(xù)看看dispatch的具體實現(xiàn)。

    // src/store.js // dispatch 的實現(xiàn) dispatch (_type, _payload) {// check object-style dispatchconst {type,payload} = unifyObjectStyle(_type, _payload)const action = { type, payload }// 同樣的道理,通過type獲取actions中的入口函數(shù)const entry = this._actions[type]······// 由于action是異步函數(shù)的集合,這里就用到了Promise.all,來合并多個promise方法并執(zhí)行const result = entry.length > 1? Promise.all(entry.map(handler => handler(payload))): entry[0](payload)return result.then(res => {try {this._actionSubscribers.filter(sub => sub.after).forEach(sub => sub.after(action, this.state))} catch (e) {if (process.env.NODE_ENV !== 'production') {console.warn(`[vuex] error in after action subscribers: `)console.error(e)}}return res}) }

    到這里,我們就把整個store中狀態(tài)存儲和狀態(tài)變更的流程系統(tǒng)的串聯(lián)了一遍,讓我們對Vuex內(nèi)部的機智有個簡單的認(rèn)識,最后我們根據(jù)我們對Vuex的理解來實現(xiàn)一個簡單的Vuex。

    // store.js let Vue// 定義store類 class Store{constructor(options = {}) {this.$options = optionsthis._mutations = options.mutationsthis._actions = options.actionsthis._wrappedGetters = options.getters// 定義computedconst computed = {}this.getters = {}const store = thisObject.keys(this._wrappedGetters).forEach(key => {// 獲取用戶定義的gettersconst fn = store._wrappedGetters[key]// 轉(zhuǎn)換為computed可以使用無參數(shù)形式computed[key] = function() {return fn(store.state)}// 為getters定義只讀屬性Object.defineProperty(store.getters, key {get:() => store._vm[key]})})// state的響應(yīng)式實現(xiàn)this._vm = new Vue({data: {// 加兩個$,Vue不做代理$$state: options.state},computed // 添加計算屬性})this.commit = this.commit.bind(this)this.dispatch = this.dispatch.bind(this)}// 存取器,獲取store.state ,只通過get形式獲取,而不是直接this.xxx, 達(dá)到對stateget state() {return this._vm._data.$$state}set state(v) {// 如果用戶不通過commit方式來改變state,就可以在這里做一控制}// commit的實現(xiàn)commit(type, payload) {const entry = this._mutations[type]if (entry) {entry(this.state, payload)}}// dispatch的實現(xiàn)dispatch(type, payload) {const entry = this._actions[type]if (entry) {entry(this, payload)}} }// 實現(xiàn)install function install(_Vue) {Vue = _VueVue.mixin({beforeCreate() {if (this.$options.store) {Vue.prototype.$Store = this.$options.store // 這樣就可以使用 this.$store}}}) }// 導(dǎo)出Vuex對象 export default {Store,install }

    全部文章鏈接

    Vue組件通信原理剖析(一)事件總線的基石 on和on和onemit
    Vue組件通信原理剖析(二)全局狀態(tài)管理Vuex
    Vue組件通信原理剖析(三)provide/inject原理分析

    最后喜歡我的小伙伴也可以通過關(guān)注公眾號“劍指大前端”,或者掃描下方二維碼聯(lián)系到我,進(jìn)行經(jīng)驗交流和分享,同時我也會定期分享一些大前端干貨,讓我們的開發(fā)從此不迷路。

    總結(jié)

    以上是生活随笔為你收集整理的Vue组件通信原理剖析(二)全局状态管理Vuex的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 国产精品乱码一区二区视频 | 视频精品一区 | 69成人网| 成人做爰的视频 | 久久久久爱 | 在线免费看mv的网站入口 | 熟女一区二区三区视频 | 潘金莲一级淫片aaaaa | 中文字幕在线免费看线人 | 中文字幕一区二区三区乱码在线 | 日韩欧美视频在线免费观看 | 亚洲精品国产手机 | 奇米在线777 | 国产黑丝在线播放 | 最新天堂av | 香蕉视频免费看 | 欧美精品国产一区二区 | ktv做爰视频一区二区 | 欧美日韩在线免费播放 | 特级西西444www大精品视频 | 精品视频在线观看免费 | 屁屁影院国产第一页 | 涩涩屋视频在线观看 | 久久精品欧美视频 | 免费黄色短片 | 操女人逼逼视频 | 欧美变态网站 | 福利91 | 亚洲逼图| 性欧美一区 | 亚洲特黄毛片 | 各种含道具高h调教1v1男男 | 丝袜熟女一区二区 | 日本一区二区三区在线观看视频 | 国产一区二区三区在线免费观看 | 精品久久9999| 欧美熟妇7777一区二区 | 国产999在线观看 | 欧美日韩一区不卡 | 欧美成人不卡视频 | 在线观看免费高清 | aaa在线 | 亚洲第一自拍 | 男人看片网站 | 69国产精品视频 | 中文在线天堂网 | 91天堂在线观看 | 麻豆av一区二区三区久久 | 在线观看天堂av | 国产乱码精品一区二区三区忘忧草 | 一级的大片 | 国产视频手机在线 | 91免费国产在线 | 亚洲日批视频 | 91tv国产成人福利 | 中文字幕麻豆 | 成人免费黄色网 | 日韩在线观看视频免费 | 日韩激情视频在线 | 禁断介护av一区二区 | 91精品黄色| 成人夜间视频 | 国产精品天干天干 | 高潮videossex高潮 | 国产精品久久91 | 免费一级淫片aaa片毛片a级 | 高清毛片aaaaaaaaa郊外 | 天天草天天操 | 波多野结衣亚洲一区二区 | 成人欧美一区二区三区在线播放 | 亚洲av无一区二区三区久久 | 丰满少妇麻豆av苏语棠 | 麻豆中文字幕 | 日韩一级免费视频 | 亚洲xx网 | 人人免费操 | 国产无遮挡又黄又爽在线观看 | 国产视频一区在线 | 又色又爽又黄18网站 | 亚洲女优视频 | 涩涩视频在线观看免费 | 黄色av毛片| 精品一区二区三区人妻 | 96人xxxxxxxxx69| 国产私人影院 | 国产青青青 | 外国电影免费观看高清完整版 | 涩涩成人网 | 久久久久久久久网站 | 色男人av | 国产高清成人 | 亚洲裸体视频 | 一本久久久久 | 日韩精品麻豆 | 亚洲精选中文字幕 | 国产真人无遮挡作爱免费视频 | 中文字幕免费在线看线人动作大片 | 久久精品无码av | 人人做 |