鏈枃鏉ヨ嚜銆婁竴鏂囪娓匳irtualDOM鐨勫惈涔変笌瀹炵幇銆�锛屽鏋滆寰椾笉閿欙紝娆㈣繋缁�Star Github浠撳簱銆�
鎽樿
闅忕潃 React 鐨勫叴璧凤紝Virtual DOM 鐨勫師鐞嗗拰瀹炵幇涔熷紑濮嬪嚭鐜板湪鍚勫ぇ鍘傞潰璇曞拰绀惧尯鐨勬枃绔犱腑銆傚叾瀹炶繖绉嶅仛娉曟棭鍦� d3.js
涓氨鏈夊疄鐜帮紝鏄� react 鐢熸�佺殑蹇�熷缓绔嬭瀹冩寮忚繘鍏ヤ簡骞垮ぇ寮�鍙戣�呯殑瑙嗚銆�
鍦ㄦ寮忓紑濮嬪墠锛屾姏鍑哄嚑涓棶棰樻潵寮曞鎬濊矾锛岃繖浜涢棶棰樹篃浼氬湪涓嶅悓鐨勫皬鑺備腑锛岄�愭瑙e喅锛�
- 馃锔� 鎬庝箞鐞嗚В VDom锛�
- 馃锔� 濡備綍琛ㄧず VDom锛�
- 馃锔� 濡備綍姣旇緝 VDom 鏍戯紝骞朵笖杩涜楂樻晥鏇存柊锛�
鈿狅笍 鏁寸悊鍚庣殑浠g爜鍜屾晥鏋滃浘鍧囧瓨鏀惧湪github.com/dongyuanxin銆�
濡備綍鐞嗚В VDom锛�
鏇剧粡锛屽墠绔父鍋氱殑浜嬫儏灏辨槸鏍规嵁鏁版嵁鐘舵�佺殑鏇存柊锛屾潵鏇存柊鐣岄潰瑙嗗浘銆傚ぇ瀹堕�愭笎鎰忚瘑鍒帮紝瀵逛簬澶嶆潅瑙嗗浘鐨勭晫闈紝棰戠箒鍦版洿鏂� DOM锛屼細閫犳垚鍥炴祦鎴栬�呴噸缁橈紝寮曞彂鎬ц兘涓嬮檷锛岄〉闈㈠崱椤裤��
鍥犳锛屾垜浠渶瑕佹柟娉曢伩鍏嶉绻佸湴鏇存柊 DOM 鏍�銆傛�濊矾涔熷緢绠�鍗曪紝鍗筹細瀵规瘮 DOM 鐨勫樊璺濓紝鍙洿鏂伴渶瑕侀儴鍒嗚妭鐐癸紝鑰屼笉鏄洿鏂颁竴妫垫爲銆傝�屽疄鐜拌繖涓畻娉曠殑鍩虹锛屽氨闇�瑕侀亶鍘� DOM 鏍戠殑鑺傜偣锛屾潵杩涜姣旇緝鏇存柊銆�
涓轰簡澶勭悊鏇村揩锛屼笉浣跨敤 DOM 瀵硅薄锛岃�屾槸鐢� JS 瀵硅薄鏉ヨ〃绀猴紝瀹冨氨鍍忔槸 JS 鍜� DOM 涔嬮棿鐨勪竴灞傜紦瀛�銆�
濡備綍琛ㄧず VDom锛�
鍊熷姪 ES6 鐨� class锛岃〃绀� VDom 璇箟鍖栨洿寮恒�備竴涓熀纭�鐨� VDom 闇�瑕佹湁鏍囩鍚嶃�佹爣绛惧睘鎬т互鍙婂瓙鑺傜偣锛屽涓嬫墍绀猴細
class Element {
constructor(tagName, props, children) {
this.tagName = tagName;
this.props = props;
this.children = children;
}
}
涓轰簡鏇存柟渚胯皟鐢紙涓嶇敤姣忔閮藉啓new
锛夛紝灏嗗叾灏佽杩斿洖瀹炰緥鐨勫嚱鏁帮細
function el(tagName, props, children) {
return new Element(tagName, props, children);
}
姝ゆ椂锛屽鏋滄兂琛ㄨ揪涓嬮潰鐨� DOM 缁撴瀯锛�
span1
鐢� VDom 灏辨槸锛�
// 瀛愯妭鐐规暟缁勭殑鍏冪礌鍙互鏄枃鏈紝涔熷彲浠ユ槸VDom瀹炰緥
const span = el("span", {}, ["span1"]);
const div = el("div", { class: "test" }, [span]);
涔嬪悗鍦ㄥ姣斿拰鏇存柊涓ゆ5 VDom 鏍戠殑鏃跺�欙紝浼氭秹鍙婂埌灏� VDom 娓叉煋鎴愮湡姝g殑 Dom 鑺傜偣銆傚洜姝わ紝涓�class Element
澧炲姞render
鏂规硶锛�
class Element {
constructor(tagName, props, children) {
this.tagName = tagName;
this.props = props;
this.children = children;
}
render() {
const dom = document.createElement(this.tagName);
// 璁剧疆鏍囩灞炴�у��
Reflect.ownKeys(this.props).forEach(name =>
dom.setAttribute(name, this.props[name])
);
// 閫掑綊鏇存柊瀛愯妭鐐�
this.children.forEach(child => {
const childDom =
child instanceof Element
? child.render()
: document.createTextNode(child);
dom.appendChild(childDom);
});
return dom;
}
}
濡備綍姣旇緝 VDom 鏍戯紝骞朵笖杩涜楂樻晥鏇存柊锛�
鍓嶉潰宸茬粡璇存槑浜� VDom 鐨勭敤娉曚笌鍚箟锛屽涓� VDom 灏变細缁勬垚涓�妫佃櫄鎷熺殑 DOM 鏍戙�傚墿涓嬮渶瑕佸仛鐨勫氨鏄細鏍规嵁涓嶅悓鐨勬儏鍐碉紝鏉ヨ繘琛屾爲涓婅妭鐐圭殑澧炲垹鏀圭殑鎿嶄綔銆傝繖涓繃绋嬫槸鍒嗕负diff
鍜�patch
锛�
- diff锛氶�掑綊瀵规瘮涓ゆ5 VDom 鏍戠殑銆佸搴斾綅缃殑鑺傜偣宸紓
- patch锛氭牴鎹笉鍚岀殑宸紓锛岃繘琛岃妭鐐圭殑鏇存柊
鐩墠鏈変袱绉嶆�濊矾锛屼竴绉嶆槸鍏� diff 涓�閬嶏紝璁板綍鎵�鏈夌殑宸紓锛屽啀缁熶竴杩涜 patch锛�鍙﹀涓�绉嶆槸 diff 鐨勫悓鏃讹紝杩涜 patch銆傜浉杈冭�岃█锛岀浜岀鏂规硶灏戜簡涓�娆¢�掑綊鏌ヨ锛屼互鍙婁笉闇�瑕佹瀯閫犺繃澶氱殑瀵硅薄锛屼笅闈㈤噰鍙栫殑鏄浜岀鎬濊矾銆�
鍙橀噺鐨勫惈涔�
灏� diff 鍜� patch 鐨勮繃绋嬶紝鏀惧叆updateEl
鏂规硶涓紝杩欎釜鏂规硶鐨勫畾涔夊涓嬶細
/**
*
* @param {HTMLElement} $parent
* @param {Element} newNode
* @param {Element} oldNode
* @param {Number} index
*/
function updateEl($parent, newNode, oldNode, index = 0) {
// ...
}
鎵�鏈変互$
寮�澶寸殑鍙橀噺锛屼唬琛ㄧ潃鐪熷疄鐨� DOM銆�
鍙傛暟index
琛ㄧずoldNode
鍦�$parent
鐨勬墍鏈夊瓙鑺傜偣鏋勬垚鐨勬暟缁勭殑涓嬫爣浣嶇疆銆�
鎯呭喌 1锛氭柊澧炶妭鐐�
濡傛灉 oldNode 涓� undefined锛岃鏄� newNode 鏄竴涓柊澧炵殑 DOM 鑺傜偣銆傜洿鎺ュ皢鍏惰拷鍔犲埌 DOM 鑺傜偣涓嵆鍙細
function updateEl($parent, newNode, oldNode, index = 0) {
if (!oldNode) {
$parent.appendChild(newNode.render());
}
}
鎯呭喌 2锛氬垹闄よ妭鐐�
濡傛灉 newNode 涓� undefined锛岃鏄庢柊鐨� VDom 鏍戜腑锛屽綋鍓嶄綅缃病鏈夎妭鐐癸紝鍥犳闇�瑕佸皢鍏朵粠瀹為檯鐨� DOM 涓垹闄ゃ�傚垹闄ゅ氨璋冪敤$parent.removeChild()
锛岄�氳繃index
鍙傛暟锛屽彲浠ユ嬁鍒拌鍒犻櫎鍏冪礌鐨勫紩鐢細
function updateEl($parent, newNode, oldNode, index = 0) {
if (!oldNode) {
$parent.appendChild(newNode.render());
} else if (!newNode) {
$parent.removeChild($parent.childNodes[index]);
}
}
鎯呭喌 3锛氬彉鍖栬妭鐐�
瀵规瘮 oldNode 鍜� newNode锛屾湁 3 绉嶆儏鍐碉紝鍧囧彲瑙嗕负鏀瑰彉锛�
- 鑺傜偣绫诲瀷鍙戠敓鍙樺寲锛氭枃鏈彉鎴� vdom锛泇dom 鍙樻垚鏂囨湰
- 鏂版棫鑺傜偣閮芥槸鏂囨湰锛屽唴瀹瑰彂鐢熸敼鍙�
- 鑺傜偣鐨勫睘鎬у�煎彂鐢熷彉鍖�
棣栧厛锛屽�熷姪Symbol
鏇村ソ鍦拌涔夊寲澹版槑杩欎笁绉嶅彉鍖栵細
const CHANGE_TYPE_TEXT = Symbol("text");
const CHANGE_TYPE_PROP = Symbol("props");
const CHANGE_TYPE_REPLACE = Symbol("replace");
閽堝鑺傜偣灞炴�у彂鐢熸敼鍙橈紝娌℃湁鐜版垚鐨� api 渚涙垜浠壒閲忔洿鏂般�傚洜姝ゅ皝瑁�replaceAttribute
锛屽皢鏂� vdom 鐨勫睘鎬х洿鎺ユ槧灏勫埌 dom 缁撴瀯涓婏細
function replaceAttribute($node, removedAttrs, newAttrs) {
if (!$node) {
return;
}
Reflect.ownKeys(removedAttrs).forEach(attr => $node.removeAttribute(attr));
Reflect.ownKeys(newAttrs).forEach(attr =>
$node.setAttribute(attr, newAttrs[attr])
);
}
缂栧啓checkChangeType
鍑芥暟鍒ゆ柇鍙樺寲鐨勭被鍨嬶紱濡傛灉娌℃湁鍙樺寲锛屽垯杩斿洖绌猴細
function checkChangeType(newNode, oldNode) {
if (
typeof newNode !== typeof oldNode ||
newNode.tagName !== oldNode.tagName
) {
return CHANGE_TYPE_REPLACE;
}
if (typeof newNode === "string") {
if (newNode !== oldNode) {
return CHANGE_TYPE_TEXT;
}
return;
}
const propsChanged = Reflect.ownKeys(newNode.props).reduce(
(prev, name) => prev || oldNode.props[name] !== newNode.props[name],
false
);
if (propsChanged) {
return CHANGE_TYPE_PROP;
}
return;
}
鍦�updateEl
涓紝鏍规嵁checkChangeType
杩斿洖鐨勫彉鍖栫被鍨嬶紝鍋氬搴旂殑澶勭悊銆傚鏋滅被鍨嬩负绌猴紝鍒欎笉杩涜澶勭悊銆傚叿浣撻�昏緫濡備笅锛�
function updateEl($parent, newNode, oldNode, index = 0) {
let changeType = null;
if (!oldNode) {
$parent.appendChild(newNode.render());
} else if (!newNode) {
$parent.removeChild($parent.childNodes[index]);
} else if ((changeType = checkChangeType(newNode, oldNode))) {
if (changeType === CHANGE_TYPE_TEXT) {
$parent.replaceChild(
document.createTextNode(newNode),
$parent.childNodes[index]
);
} else if (changeType === CHANGE_TYPE_REPLACE) {
$parent.replaceChild(newNode.render(), $parent.childNodes[index]);
} else if (changeType === CHANGE_TYPE_PROP) {
replaceAttribute($parent.childNodes[index], oldNode.props, newNode.props);
}
}
}
鎯呭喌 4锛氶�掑綊瀵瑰瓙鑺傜偣鎵ц Diff
濡傛灉鎯呭喌 1銆�2銆�3 閮芥病鏈夊懡涓紝閭d箞璇存槑褰撳墠鏂版棫鑺傜偣鑷韩娌℃湁鍙樺寲銆傛鏃讹紝闇�瑕侀亶鍘嗗畠浠紙Virtual Dom锛夌殑children
鏁扮粍锛圖om 瀛愯妭鐐癸級锛岄�掑綊杩涜澶勭悊銆�
浠g爜瀹炵幇闈炲父绠�鍗曪細
function updateEl($parent, newNode, oldNode, index = 0) {
let changeType = null;
if (!oldNode) {
$parent.appendChild(newNode.render());
} else if (!newNode) {
$parent.removeChild($parent.childNodes[index]);
} else if ((changeType = checkChangeType(newNode, oldNode))) {
if (changeType === CHANGE_TYPE_TEXT) {
$parent.replaceChild(
document.createTextNode(newNode),
$parent.childNodes[index]
);
} else if (changeType === CHANGE_TYPE_REPLACE) {
$parent.replaceChild(newNode.render(), $parent.childNodes[index]);
} else if (changeType === CHANGE_TYPE_PROP) {
replaceAttribute($parent.childNodes[index], oldNode.props, newNode.props);
}
} else if (newNode.tagName) {
const newLength = newNode.children.length;
const oldLength = oldNode.children.length;
for (let i = 0; i < newLength || i < oldLength; ++i) {
updateEl(
$parent.childNodes[index],
newNode.children[i],
oldNode.children[i],
i
);
}
}
}
鏁堟灉瑙傚療
灏�github.com/dongyuanxin/pure-virtual-dom鐨勪唬鐮� clone 鍒版湰鍦帮紝Chrome 鎵撳紑index.html
銆�
鏂板 dom 鑺傜偣.gif:
鏇存柊鏂囨湰鍐呭.gif锛�
鏇存敼鑺傜偣灞炴��.gif锛�
鈿狅笍 缃戦�熻緝鎱㈢殑鍚屽璇风Щ姝� github 浠撳簱