實現簡易版react中createElement和render方法


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'));

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM