學習過框架尤爲是VUE、React的確定都知道Virtual DOM這個概念。由於我也很想知道而且瞭解它是一個什麼東西,因此我打算把本身學習的分享個你們。若有錯誤,請你們指明。node
首先,說一下什麼是虛擬DOM。算法
其實就是一個JS的對象。咱們先來簡單的實現一個虛擬DOM。咱們使用過React的都知道createElement這一個函數、Vue都知道render或者是「h」,這樣一個函數。咱們先來建立一個createElement函數。bash
/**
* [createElement 用來建立DOM節點]
* @param {[type]} type [元素類型(名稱)]
* @param {[type]} props [描述信息]
* @param {[type]} children [子節點]
* @return {[type]} [description]
*/
function createElement(type, props, children) {
// 返回一個Element對象。
return new Element(type, props, children);
}
複製代碼
<div class="vdom">561651</div>
type: div
props: class="vdom"
children: 561651
複製代碼
元素對象(Element),用來表示一個元素。app
class Element {
constructor(type, props, children) {
this.type = type;
this.props = props;
this.children = children;
}
}
複製代碼
let vDom = createElement("ul", {class: "dawd"}, [
createElement("li", {class: "dawd"}, ["1"]),
createElement("li", {class: "dawd"}, ["2"]),
createElement("li", {class: "dawd"}, ["3"])
]);
複製代碼
已經基本描述出了DOM的樹形結構。下面咱們來根據虛擬DOM建立真實的DOM。在這以前咱們先建立元素節點(單個元素)。
/**
* [createNode 建立單個元素]
* @param {[type]} node [元素節點]
* @return {[type]} [真實的DOM元素]
*/
function createNode(node){
// 根據類型建立元素
let el = document.createElement(node.type);
for (key in node.props) {
// 遍歷屬性
if(key === "value"){
// 只有input還有textarea須要value屬性
if(node.type.toUpperCase() === "INPUT" || node.type.toUpperCase() === "TEXTAREA"){
el.value = node.props[key];
}
}else {
// 設置屬性
el.setAttribute(key, node.props[key]);
}
}
return el;
}
複製代碼
根據單個元素組成DOM樹框架
function createDom(node) {
let root = createNode(node);
if(node.children && node.children.length > 0){
// 遍歷子元素
node.children.forEach( function(element) {
if(element instanceof Element){
// 節點
root.appendChild( createDom(element) );
}else {
// 文本
root.appendChild( document.createTextNode(element) );
}
});
}
return root;
}
複製代碼
根據虛擬DOM生成的真實DOM dom
如今只是生成了真實的DOM可是尚未真正的掛載到DOM樹上,沒有顯示。let dom = createDom(vDom);
document.getElementsByTagName("body")[0].appendChild(dom);
複製代碼
再試一下input元素函數
let vDom = createElement("ul", {class: "dawd"}, [
createElement("li", {class: "dawd"}, [
createElement("input", {type: "radio",value: "1651"},[]),
createElement("input", {type: "text",value: "1651"},[])
])
]);
複製代碼
真實DOM post
顯示效果咱們再來一個複雜一點的來驗證是否正確。性能
createElement("div", {class: "div"}, [
createElement("ul", {class: "ul"}, [
createElement("li", {class: "li"},[createElement("input", {type: "radio",value: "1651"},["單選"])]),
createElement("li", {class: "li"},[createElement("input", {type: "text",value: "1651"},[])]),]),
createElement("div", {class: "div"}, [
createElement("p", {class: "p"},[
createElement("span", {class: "span"},["我是span"])]),
createElement("a", {class: "a",href: "https://juejin.im/editor/drafts/5cf3c75de51d45572c05fff3"},[
createElement("span", {class: "span"},["我是超連接裏面的span"])]),
createElement("img", {class: "img",src: "http://g.hiphotos.baidu.com/image/h%3D300/sign=b5e4c905865494ee982209191df4e0e1/c2cec3fdfc03924590b2a9b58d94a4c27d1e2500.jpg",alt: "虛擬DOM圖片",title: "虛擬的DOM"},[])
]),
]);
複製代碼
我會盡快寫一篇有關DOM diff算法 的文章,但願大家能耐心等候。學習