我自己的理解
虚拟dom:就是 通过js对象表示的DOM结构。
尝试虚拟dom的原因:操作一次的dom的渲染成本远远超过与操作虚拟dom的成本,操作dom是最耗费性能的,所以通过将dom对比操作放在js层,提高效率,也就是虚拟dom。
下面我们通过控制台打印来看一下,一个dom元素的复杂程度。
var div=document.createElement('div')
var result=''
for(let item in div){
result+='|'+item;
}
console.log(result)
//|align|title|lang|translate|dir|dataset|hidden|tabIndex|accessKey|draggable
|spellcheck|autocapitalize|contentEditable|isContentEditable|offsetParent
|offsetTop|offsetLeft|offsetWidth|offsetHeight|style|innerText|outerText
|onabort|onblur|oncancel|oncanplay|oncanplaythrough|onchange||onclose
|oncontextmenu|oncuechange|ondblclick|ondrag|ondragend|ondragenter|ondragleave
|ondragover|ondragstart|ondrop|ondurationchange|onemptied|onended||onfocus
|oninput|oninvalid|onkeydown|onkeypress|onkeyup||eddata|edmetadata
|start|onmousedown|onmouseenter|onmouseleave|onmousemove|onmouseout|onmouseover
|onmouseup|onmousewheel|onpause|onplay|onplaying|onprogress|onratechange|onreset
|onresize|onscroll|onseeked|onseeking|onselect|onstalled|onsubmit|onsuspend
|ontimeupdate|ontoggle|onvolumechange|onwaiting|onwheel|onauxclick|ongotpointercapture|
onlostpointercapture|onpointerdown|onpointermove|onpointerup|onpointercancel|
onpointerover|onpointerout|onpointerenter|onpointerleave|nonce|click|focus|blur|
inputMode|namespaceURI|prefix|localName|tagName|id|className|classList|slot|attributes|
shadowRoot|assignedSlot|innerHTML|outerHTML|scrollTop|scrollLeft|scrollWidth|
scrollHeight|clientTop|clientLeft|clientWidth|clientHeight|onbeforecopy|onbeforecut|
onbeforepaste|oncopy|oncut|onpaste|onsearch|onselectstart|previousElementSibling|
nextElementSibling|children|firstElementChild|lastElementChild|childElementCount|
onwebkitfullscreenchange|onwebkitfullscreenerror|setPointerCapture|releasePointerCapture|
hasPointerCapture|hasAttributes|getAttributeNames|getAttribute|getAttributeNS|setAttribute|
setAttributeNS|removeAttribute|removeAttributeNS|hasAttribute|hasAttributeNS|getAttributeNode|
getAttributeNodeNS|setAttributeNode|setAttributeNodeNS|removeAttributeNode|closest|matches|
webkitMatchesSelector|attachShadow|getElementsByTagName|getElementsByTagNameNS|getElementsByClassName|
insertAdjacentElement|insertAdjacentText|insertAdjacentHTML|requestPointerLock|getClientRects|
getBoundingClientRect|scrollIntoView|scrollIntoViewIfNeeded|animate|before|after|replaceWith|remove|
prepend|append|querySelector|querySelectorAll|webkitRequestFullScreen|webkitRequestFullscreen|attributeStyleMap|
scroll|scrollTo|scrollBy|createShadowRoot|getDestinationInsertionPoints|computedStyleMap|ELEMENT_NODE|ATTRIBUTE_NODE|
TEXT_NODE|CDATA_SECTION_NODE|ENTITY_REFERENCE_NODE|ENTITY_NODE|PROCESSING_INSTRUCTION_NODE|COMMENT_NODE|
document_NODE|document_TYPE_NODE|document_FRAGMENT_NODE|NOTATION_NODE|document_POSITION_DISConNECTED|
document_POSITION_PRECEDING|document_POSITION_FOLLOWING|document_POSITION_ConTAINS|
document_POSITION_CONTAINED_BY|document_POSITION_IMPLEMENTATION_SPECIFIC|nodeType|nodeName
|baseURI|isConnected|ownerdocument|parentNode|parentElement|childNodes|firstChild|lastChild
|previousSibling|nextSibling|nodevalue|textContent|hasChildNodes|getRootNode|normalize
|cloneNode|isEqualNode|isSameNode|comparedocumentPosition|contains|lookupPrefix|
lookupNamespaceURI|isDefaultNamespace|insertBefore|appendChild|replaceChild|removeChild|addEventListener|removeEventListener|dispatchEvent光是第一层外层的属性打印出来就如此之多,可想而知,对比虚拟dom的几个属性,dom的操作比虚拟dom 所耗费的性能多得多。
DOM 操作是“昂贵”的,js 运行效率高,所以我们尽量减少 DOM 操作,而不是“推倒重来”,项目越复杂,影响就越严重,所以使用 vdom 即可解决这个问题
下面是html代码例子以及对应的虚拟dom结构。
html代码:
- Item 1
- Item 2
- Item 3
Virtual DOM 算法:包括几个步骤:
用 Javascript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中
当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异
把2所记录的差异应用到步骤1所构建的真正的DOM树上,视图就更新了
根据vdom的描述,下面使用jQuery来模拟实现上面的代码
var data = [
{
name: '张三',
age: '20',
address: '北京'
},
{
name: '李四',
age: '21',
address: '上海'
},
{
name: '王五',
age: '22',
address: '广州'
}
]
// 渲染函数
function render(data) {
var $container = $('#container')
// 清空容器,重要!!!
$container.html('')
// 拼接 table
var $table = $('| name | age | address | /tr>')) data.forEach(function (item) { $table.append($('
| ' + item.name + ' | ' + item.age + ' | ' + item.address + ' | /tr>')) }) // 渲染到页面 $container.append($table) } $('#btn-change').click(function () { data[1].age = 30 data[2].address = '深圳' // re-render 再次渲染 render(data) }) // 页面加载完立刻执行(初次渲染) render(data)



