在 ./src/modules
裏面,定義了一系列的模塊 , 這些模塊定義了相應的鉤子 。這些鉤子會在 patch
的不一樣階段觸發,以完成相應模塊的功能處理javascript
瞭解生命週期更多的內容,請查看 鉤子
主要的模塊有 :html
其中 attributes
class
dataset
props
四個比較簡單,都是定義了 create
update
兩個鉤子,vue
eventlisteners
hero
style
這三個模塊就複雜一點。java
另外 module.ts
只是定義了這些模塊所用到的一些鉤子node
// 定義模塊的鉤子 export interface Module { pre: PreHook; create: CreateHook; update: UpdateHook; destroy: DestroyHook; remove: RemoveHook; post: PostHook; }
接下來咱們來看看其餘的模塊git
文件位置 : ./src/modules/attributes.ts
github
咱們先拉到最後segmentfault
// 建立以及更新的鉤子 export const attributesModule = { create: updateAttrs, update: updateAttrs } as Module; export default attributesModule;
attributesModule
導出了兩個方法, 都是調用了 updateAttrs
。dom
這個表示,在建立元素的時候,以及更新的時候,都會觸發這兩個鉤子,來更新 attribute
。函數
updateAttrs
主要接受兩個參數,oldVnode
、vnode
。
主要邏輯以下:
vnode
全部的屬性,判斷在 oldVnode
中是否相等,修改不相等的屬性vnode
的屬性代碼以下:
/** * 更新屬性 */ function updateAttrs(oldVnode: VNode, vnode: VNode): void { var key: string, elm: Element = vnode.elm as Element, oldAttrs = (oldVnode.data as VNodeData).attrs, attrs = (vnode.data as VNodeData).attrs; if (!oldAttrs && !attrs) return; if (oldAttrs === attrs) return; oldAttrs = oldAttrs || {}; attrs = attrs || {}; // update modified attributes, add new attributes // 遍歷新的屬性,修改不相等的 for (key in attrs) { const cur = attrs[key]; const old = oldAttrs[key]; if (old !== cur) { if (cur === true) { elm.setAttribute(key, ''); } else if (cur === false) { elm.removeAttribute(key); } else { if (key.charCodeAt(0) !== xChar) { // 若是不是 x 開頭 elm.setAttribute(key, cur); } else if (key.charCodeAt(3) === colonChar) { // Assume xml namespace elm.setAttributeNS(xmlNS, key, cur); } else if (key.charCodeAt(5) === colonChar) { // Assume xlink namespace elm.setAttributeNS(xlinkNS, key, cur); } else { elm.setAttribute(key, cur); } } } } // remove removed attributes // use `in` operator since the previous `for` iteration uses it (.i.e. add even attributes with undefined value) // the other option is to remove all attributes with value == undefined // 刪除多餘的屬性 for (key in oldAttrs) { if (!(key in attrs)) { elm.removeAttribute(key); } } }
文件位置 : ./src/modules/class.ts
與 attribute
相似 , class
也是定義了 create
和 update
兩個鉤子,統一由 updateClass
處理
這塊邏輯比較簡單 ,直接看代碼吧
function updateClass(oldVnode: VNode, vnode: VNode): void { var cur: any, name: string, elm: Element = vnode.elm as Element, oldClass = (oldVnode.data as VNodeData).class, klass = (vnode.data as VNodeData).class; // 新老的 className 都沒有 if (!oldClass && !klass) return; // 新老的 className 沒變 if (oldClass === klass) return; oldClass = oldClass || {}; klass = klass || {}; // 刪除不存在與新的 classList 的 className for (name in oldClass) { if (!klass[name]) { elm.classList.remove(name); } } // 新增 或刪除 class for (name in klass) { cur = klass[name]; if (cur !== oldClass[name]) { (elm.classList as any)[cur ? 'add' : 'remove'](name); } } }
文件位置 : ./src/modules/dataset.ts
與 attribute
相似 , dataset
也是定義了 create
和 update
兩個鉤子,統一由 updateDataset
處理
這塊邏輯比較簡單 ,直接看代碼吧
const CAPS_REGEX = /[A-Z]/g; /** * 更新或建立 dataset */ function updateDataset(oldVnode: VNode, vnode: VNode): void { let elm: HTMLElement = vnode.elm as HTMLElement, oldDataset = (oldVnode.data as VNodeData).dataset, dataset = (vnode.data as VNodeData).dataset, key: string; // 不變的狀況下不處理 if (!oldDataset && !dataset) return; if (oldDataset === dataset) return; oldDataset = oldDataset || {}; dataset = dataset || {}; const d = elm.dataset; // 刪除多餘的 dataset for (key in oldDataset) { if (!dataset[key]) { if (d) { if (key in d) { delete d[key]; } } else { // 將駝峯式改成中劃線分割 eg: userName ----> user-name elm.removeAttribute( 'data-' + key.replace(CAPS_REGEX, '-$&').toLowerCase() ); } } } // 修改有變化的 dataset for (key in dataset) { if (oldDataset[key] !== dataset[key]) { if (d) { d[key] = dataset[key]; } else { elm.setAttribute( // 將駝峯式改成中劃線分割 eg: userName ----> user-name 'data-' + key.replace(CAPS_REGEX, '-$&').toLowerCase(), dataset[key] ); } } } }
文件位置 : ./src/modules/props.ts
與 attribute
相似 , props
也是定義了 create
和 update
兩個鉤子,統一由 updateProps
處理
這塊邏輯比較簡單 ,直接看代碼吧
function updateProps(oldVnode: VNode, vnode: VNode): void { var key: string, cur: any, old: any, elm = vnode.elm, oldProps = (oldVnode.data as VNodeData).props, props = (vnode.data as VNodeData).props; if (!oldProps && !props) return; if (oldProps === props) return; oldProps = oldProps || {}; props = props || {}; // 刪除多餘的屬性 for (key in oldProps) { if (!props[key]) { delete (elm as any)[key]; } } // 添加新增的屬性 for (key in props) { cur = props[key]; old = oldProps[key]; // key爲value的狀況,再判斷是否value有變化 // key不爲value的狀況,直接更新 if (old !== cur && (key !== 'value' || (elm as any)[key] !== cur)) { (elm as any)[key] = cur; } } }
eventlisteners 這一塊內容稍微多一點,故將其獨立出來一個章節。 傳送門 : 事件
待續。。。
待續。。。