## 什麼是vdom ##javascript
<ul id="list"> <li class="item">Item 1</li> <li class="item">Item 2</li> </ul>
用js來模擬css
{ tag:"ul", attrs:{ id:"list" }, children:[ { tag:"li", attrs:{ className: "item"}, //class是js的保留字,因此用className children:['Item 1'] },{ tag:"li", attrs:{ className: "item"}, children:['Item 2'] } ] }
//Jquery的實現 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.4.0/jquery.min.js"></script> <script type="text/javascript"> var dataList = [ { name:'111', age:1 },{ name:'222', age:2 },{ name:'333', age:3 },{ name:'444', age:4 }, ] $(document).ready(function () { function render(data){ var $container = $('#container') $container.html('') //拼接tabel $table = $('<table>') $table.append($('<tr><td>name</td><td>age</td></tr>')) //渲染到頁面 data.forEach(item => { $table.append($(`<tr><td>${item.name}</td><td>${item.age}</td></tr>`)) }); $container.append($table) } render(dataList) $("#btn-change").click(function(){ dataList[1].age=30 //每次修改數據都會清空dom,而後重繪表格 render(dataList) }) }) </script> </head> <body> <div id="container"></div> <button id="btn-change">修改數據</button> </body> </html>
上述辦法遇到的問題html
snabbdom
爲何是snabbdom.js
因爲虛擬dom有那麼多的好處並且現代前端框架中react和vue均不一樣程度的使用了虛擬dom的技術,所以經過一個簡單的 庫賴學習虛擬dom技術就十分必要了,至於爲何會選擇snabbdom.js這個庫呢?緣由主要有兩個:前端
源碼簡短,整體代碼行數不超過500行。
著名的vue的虛擬dom實現也是參考了snabbdom.js的實現。vue
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom.js"></script> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-class.js"></script> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-props.js"></script> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-style.js"></script> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-eventlisteners.js"></script> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/h.min.js"></script> </head> <body> <div id="container"></div> <button id="btn-change">修改數據</button> <script type="text/javascript"> var snabbdom = window.snabbdom //定義patch var patch = snabbdom.init([ snabbdom_class, snabbdom_props, snabbdom_style, snabbdom_eventlisteners ]) var h = snabbdom.h var container = document.getElementById("container") //生成vnode var vnode= h('ul#list',{},[ h('li.item',{},'Item 1'), h('li.item',{},'Item 2') ]) patch(container,vnode) document.getElementById("btn-change").addEventListener('click',function(){ console.log("111") var newVnode = h('ul#list',{},[ h('li.item',{},'Item 1'), h('li.item',{},'Item B'), h('li.item',{},'Item 3') ]) patch(vnode,newVnode) }) </script> </body> </html>
//修改數據只是修改了 第二個item 第三,第一個數據沒變化(F12查看Element 第一個item沒有閃爍)java
diff命令是linux系統自帶的基礎命令
git diff 判斷文本文件哪裏被修改了
diff算法一直都在,並非由於react、vue纔出現的node
只須要明白react
經過VNode建立一個真實的DOM的流程jquery
function createElement(vnode){ var tag= vnode.tag var attrs = vnode.attrs||{} var children = vnode.children || [] if(!tag){ return null } var elem = document.createElement(tag) var attrName for(attrName in attrs){ if(attrs.hasOwnProperty(attrName)){ elem.setAttribute(attrName,attrs[attrName]) } } children.forEach(childNode => { elem.appendChild(createElement(childNode)) }); //返回真實的Dom return elem }
path(vnode,newVnode) 的實現,linux
function updateChildren(vnode,newVnode){ var children = vnode.children || [] var newChildren = newVnode.children || [] //遍歷現有的children children.forEach((child,index )=> { var newChild = newChildren[index] if(newChild == null){ return } if(child.tag === newChild.tag){ updateChildren(child,newChild) }else{ replaceNode(child,newChild) } }); } function replaceNode(vnode,newVnode){ var elem = vnode.elem var newElem = createElement(newVnode) }
不單單是以上的內容,還有如下的內容