寫文章不容易,點個贊唄兄弟
專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧
研究基于 Vue版本 【2.5.17】
如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關注公眾號也可以吧
【Vue原理】Mixins - 源碼版
今天探索的是 mixins 的源碼,mixins 根據不同的選項類型會做不同的處理
篇幅會有些長,你知道的,有很多種選項類型的嘛,但不是很難。只是涉及源碼難免會有些煩,
不過這篇文章也不是給你直接看的,是為了可以讓你學習源碼的時候提供微薄幫助而已
如果不想看源碼的,可以看我的白話版
【Vue原理】Mixin - 白話版
我們也是要帶著兩個問題開始
1、什么時候開始合并
2、怎么合并
如果你覺得排版難看,請點擊下面原文鏈接 或者 關注公眾號【神仙朱】
什么時候合并合并分為兩種
1、全局mixin 和 基礎全局options 合并
這個過程是先于你調用 Vue 時發生的,也是必須是先發生的。這樣mixin 才能合并上你的自定義 options
Vue.mixin = function(mixin) { this.options = mergeOptions( this.options, mixin ); return this };
基礎全局options 是什么?
就是 components,directives,filters 這三個,一開始就給設置在了 Vue.options 上。所以這三個是最先存在全局options
Vue.options = Object.create(null); ["component","directive","filter"].forEach(function(type) { Vue.options[type + "s"] = Object.create(null); });
這一步,是調用 Vue.mixin 的時候就馬上合并了,然后這一步完成 以后,舉個栗子
全局選項就變成下面這樣,然后每個Vue實例都需要和這全局選項合并
2、全局options和 自定義options合并
在調用Vue 的時候,首先進行的就是合并
function Vue(options){ vm.$options = mergeOptions( { 全局component, 全局directive, 全局filter 等....}, options , vm ); // ...處理選項,生成模板,掛載DOM 等.... }
options 就是你自己傳進去的對象參數,然后跟 全局options 合并,全局options 是哪些,也已經說過了
怎么合并上面的代碼一直出現一個函數 mergeOptions,他便是合并的重點
來看源碼
1、mergeOptionsfunction mergeOptions(parent, child, vm) { // 遍歷mixins,parent 先和 mixins 合并,然后在和 child 合并 if (child.mixins) { for (var i = 0, l = child.mixins.length; i < l; i++) { parent = mergeOptions(parent, child.mixins[i], vm); } } var options = {}, key; // 先處理 parent 的 key, for (key in parent) { mergeField(key); } // 遍歷 child 的key ,排除已經處理過的 parent 中的key for (key in child) { if (!parent.hasOwnProperty(key)) { mergeField(key); } } // 拿到相應類型的合并函數,進行合并字段,strats 請看下面 function mergeField(key) { // strats 保存著各種字段的處理函數,否則使用默認處理 var strat = strats[key] || defaultStrat; // 相應的字段處理完成之后,會完成合并的選項 options[key] = strat(parent[key], child[key], vm, key); } return options }
這段代碼看上去有點繞,其實無非就是
1、先遍歷合并 parent 中的key,保存在變量options
2、再遍歷 child,合并補上 parent 中沒有的key,保存在變量options
3、優先處理 mixins ,但是過程跟上面是一樣的,只是遞歸處理而已
在上面實例初始化時的合并, parent 就是全局選項,child 就是組件自定義選項,因為 parent 權重比 child 低,所以先處理 parent 。
“公司開除程序猿,也是先開始作用較低。。”
重點其實在于 各式各樣的處理函數 strat,下面將會一一列舉
2、defaultStrats這段函數言簡意賅,意思就是優先使用組件的options
組件options>組件 mixin options>全局options
var defaultStrats= function(parentVal, childVal) { return childVal === undefined ? parentVal : childVal };3、data
我們先默認 data 的值是一個函數,簡化下源碼 ,但是其實看上去還是會有些復雜
不過我們主要了解他的工作過程就好了
1、兩個data函數 組裝成一個函數
2、合并 兩個data函數執行返回的 數據對象
strats.data = function(parentVal, childVal, vm) { return mergeDataOrFn( parentVal, childVal, vm ) }; function mergeDataOrFn(parentVal, childVal, vm) { return function mergedInstanceDataFn() { var childData = childVal.call(vm, vm) var parentData = parentVal.call(vm, vm) if (childData) { return mergeData(childData, parentData) } else { return parentData } } } function mergeData(to, from) { if (!from) return to var key, toVal, fromVal; var keys = Object.keys(from); for (var i = 0; i < keys.length; i++) { key = keys[i]; toVal = to[key]; fromVal = from[key]; // 如果不存在這個屬性,就重新設置 if (!to.hasOwnProperty(key)) { set(to, key, fromVal); } // 存在相同屬性,合并對象 else if (typeof toVal =="object" && typeof fromVal =="object) { mergeData(toVal, fromVal); } } return to }4、生命鉤子
把所有的鉤子函數保存進數組,重要的是數組子項的順序
順序就是這樣
[ 全局 mixin - created, 組件 mixin-mixin - created, 組件 mixin - created, 組件 options - created ]
所以當數組執行的時候,正序遍歷,就會先執行全局注冊的鉤子,最后是 組件的鉤子
function mergeHook(parentVal, childVal) { var arr; arr = childVal ? // concat 不只可以拼接數組,什么都可以拼接 ( parentVal ? // 為什么parentVal 是個數組呢 // 因為無論怎么樣,第一個 parent 都是{ component,filter,directive} // 所以在這里,合并的時候,肯定只有 childVal,然后就變成了數組 parentVal.concat(childVal) : ( Array.isArray(childVal) ? childVal: [childVal] ) ) : parentVal return arr } strats["created"] = mergeHook; strats["mounted"] = mergeHook; // ... 等其他鉤子5、component、directives、filters
我一直覺得這個是比較好玩的,這種類型的合并方式,我是從來沒有在項目中使用過的
原型疊加
兩個對象并沒有進行遍歷合并,而是把一個對象直接當做另一個對象的原型
這種做法的好處,就是為了保留兩個相同的字段且能訪問,避免被覆蓋
學到了學到了.....反正我是學到了
strats.components= strats.directives= strats.filters = function mergeAssets( parentVal, childVal, vm, key ) { var res = Object.create(parentVal || null); if (childVal) { for (var key in childVal) { res[key] = childVal[key]; } } return res }
就是下面這種,層層疊加的原型
6、watchwatch 的處理,也是合并成數組,重要的也是合并順序,跟 生命鉤子一樣
這樣的鉤子
[ 全局 mixin - watch, 組件 mixin-mixin - watch, 組件 mixin - watch, 組件 options - watch ]
按照正序執行,最后執行的 必然是組件的 watch
strats.watch = function(parentVal, childVal, vm, key) { if (!childVal) { return Object.create(parentVal || null) } if (!parentVal) return childVal var ret = {}; // 復制 parentVal 到 ret 中 for (var key in parentVal) { ret[key] = parentVal[key]; } for (var key$1 in childVal) { var parent = ret[key$1]; var child = childVal[key$1]; if (!Array.isArray(parent)) { parent = [parent]; } ret[key$1] = parent ? parent.concat(child) : ( Array.isArray(child) ? child: [child] ); } return ret };7、props、computed、methods
這幾個東西,是不允許重名的,合并成對象的時候,不是你死就是我活
重要的是,以誰的為主?必然是組件options 為主了
比如
組件的 props:{ name:""}
組件mixin 的 props:{ name:"", age: "" }
那么 把兩個對象合并,有相同屬性,組件的 name 會替換 mixin 的name
trats.props = strats.methods = strats.inject = strats.computed = function(parentVal, childVal, vm, key) { if (!parentVal) return childVal var ret = Object.create(null); // 把 parentVal 的字段 復制到 ret 中 for (var key in parentVal) { ret[key] = parentVal[key]; } if (childVal) { for (var key in childVal) { ret[key] = childVal[key]; } } return ret };
其實在白話版里面,就已經測試了很多例子,整個執行的流程也描述很清楚了,這里就是放個源碼供參考
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105382.html
摘要:而我覺得現在出一個白話版,是讓大家有興趣去研究源碼的時候,可以提前理清一下思路。相當于封裝,提取公共部分。顯然,今天我不是來教大家怎么用的,怎么用看文檔就好了,我是講解生命的真諦內部的工作原理。而這個不會合并,直接替換掉整個選項 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于 Vue版...
摘要:其中的標志位什么時候設置呢,是在相應的鉤子觸發之后,具體看下面源碼怎么執行鉤子呢沒錯,就是下面這個函數是自己傳入的等回調那是怎么用呢比如觸發就會這么調用很簡單不,直接拿到鉤子,然后遍歷執行,綁定上下文對象。 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于 Vue版本 【2.5.17】 ...
摘要:寫文章不容易,點個贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于版本如果你覺得排版難看,請點擊下面鏈接或者拉到下面關注公眾號也可以吧原理源碼版之創建組件今天就要開啟我 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于...
摘要:正文距離第一篇組件庫文章發布已經過去個月了,在此期間利用零零散散的時間持續更新組件庫,目前移動端組件庫已經更新大類基礎表單彈出層種組件供使用。鏈接組件庫從到開發心得主頁更改版版方案祝工作順利鄧文斌年月日正文 距離第一篇UI組件庫文章發布已經過去3個月了,在此期間利用零零散散的時間持續更新owl-ui組件庫,目前owl-ui移動端組件庫已經更新3大類(基礎、表單、彈出層)9種組件(Button...
摘要:簡介最近有點小閑置,于是乎希望寫點東西,正好自己喜歡聽歌,便決定自己寫一個音樂的簡易版。核心文件則是在在這里使用統一管理頁面切換動畫,歌曲播放狀態,歌曲進度等信息。所有對于歌曲的操作都通過來進行全局管理,然后對相應的變化做出全局改變。 Vue-QQMusic 簡介: 最近有點小閑置,于是乎希望寫點東西,正好自己喜歡聽歌,便決定自己寫一個QQ音樂的簡易版。順便進一步加深下自己對移動端的知...
閱讀 3164·2019-08-30 15:55
閱讀 2945·2019-08-30 13:46
閱讀 1447·2019-08-29 17:29
閱讀 3514·2019-08-29 11:08
閱讀 3439·2019-08-29 11:04
閱讀 1088·2019-08-28 18:20
閱讀 545·2019-08-26 13:37
閱讀 1327·2019-08-26 11:49