function createElement(type, config, children) { // 1. 創建一個對象 // 2.根據參數config修改這個對象 // 3.把children參數作為對象中props中的一個屬性 let virtureDOM = {}; virtureDOM.type = type; virtureDOM.ref = config.ref || null; virtureDOM.key = config.key || null; let props = {}; // 虛擬dom的props for (const attr in config) { // 遍歷config 把除去ref和key的屬性值復制到props中 if (attr === 'key' || attr === 'ref') continue; else props[attr] = config[attr]; } const childrenLength = arguments.length - 2;// create可以傳多個參數 第三個開始被認為是children if (childrenLength === 1) { props.children = children; // 如果只有一個 那么children就是第三個參數 } else if (childrenLength > 1) { let childArray = Array(childrenLength); // 如果不止一個,就存入childArray數組中 for (let i = 0; i < childrenLength; i++) { childArray[i] = arguments[i + 2]; } props.children = childArray; } virtureDOM.props = props; return virtureDOM; } // 把創建的對象轉為真實DOM元素最后插入到頁面中 function render(virtureDOM, container, callback) { let { type, props } = virtureDOM || {}; let realDom = document.createElement(type); for (let attr in props) { if (!props.hasOwnProperty(attr)) break; // 如果不是私有屬性 直接跳出 說明已經遍歷到原型上了 if (!props[attr]) continue; // 如果這個attr沒有有效值,那么繼續找下一個 const val = props[attr]; // 處理classname變成class if (attr === 'className') realDom.setAttribute('class', val); else if (attr === 'children') { // 處理children if (typeof val === 'string') { // 如果只有一個字符串children 那么直接渲染text出來 let text = document.createTextNode(val); realDom.appendChild(text); } else if (val instanceof Array) { // 如果children是數組, 那么就得遍歷這個數組分情況再渲染 for (let i = 0; i < val.length; i++) { if (typeof val[i] === 'string') { let text = document.createTextNode(val[i]); realDom.appendChild(text); } else { render(val[i], realDom); } } } else { // 如果children只有一個且不是數組也不是字符串 那么應該是createElement出來的虛擬dom。遞歸 render(val, realDom); } } else if (attr === 'style') { // 處理style屬性 if (val === '') continue; // style 有可能值為空字符串 for (let sty in val) { if (val.hasOwnProperty(sty)) realDom['style'][sty] = val[sty]; } } else realDom.setAttribute(attr, val); // 基於setAttribute可以讓設置的屬性表現在html的結構上 } container.appendChild(realDom); callback && callback(); } const virtureDom2 = createElement('span', {}, 'age is 18!'); const virtureDom = createElement('div', { id: 'box', className: 'lp', style: { color: 'red' }, key: 12, ref: 'refs' }, 'my name is LanPang ', virtureDom2); render(virtureDom, document.getElementById('root'), () => console.log('finish'));