react知識(二)重寫JSX編譯原理

小山芋發表於2018-06-29

呼叫方法

import {createElement, render} from './self-jsx';

let objJSX = createElement(
    'div',
    {id: 'box', className: 'box', style: {color: 'red'}},
    createElement(
        'h2',
        {className: 'title'},
        '\u7CFB\u7EDF\u63D0\u793A'
    ),
    createElement(
        'div',
        {className: 'content'},
        '\u6E29\u99A8\u63D0\u793A\uFF1A\u8BED\u6CD5\u9519\u8BEF\uFF01'
    ),
    '\u672C\u64CD\u4F5C\u5C31\u662F\u4E00\u4E2A\u6D4B\u8BD5\uFF01'
);
render(objJSX, root);
複製程式碼

createElement方法

/*
* CREATE-ELEMENT:建立JSX物件
*   引數:至少兩個 TYPE/PROPS,CHILDREN這個部分可能沒有可能有多個
*/
function createElement(type, props, ...childrens) {
  props = props || {}  // 下面要用in方法
 let ref, key;
 if ('ref' in props) {
     ref = props['ref'];
     props['ref'] = undefined;
 }
 if ('key' in props) {
     key = props['key'];
     props['key'] = undefined;
 }
 return {
     type,
     props: {
         ...props,
         children: childrens.length <= 1 ? (childrens[0] || '') : childrens
     },
     ref,
     key
 };
}
複製程式碼

render方法


function render(objJSX, container, callBack) {
 let {type, props} = objJSX,
     {children} = props;
 let newElement = document.createElement(type);
 for (let attr in props) {
     if (!props.hasOwnProperty(attr)) break;
     let value = props[attr];
     if (value == undefined) continue;//=>NULL OR UNDEFINED
     
     // 當是事件屬性的時候
        let regEvent = /^on/;
        if(regEvent.test(attr)){
            newElement.addEventListener(attr.toUpperCase().substr(2)
            ,value.bind(undefined));
            continue;
        } 
     switch (attr.toUpperCase()) {
         case 'CLASSNAME':
             newElement.setAttribute('class', value);
             break;
         case 'STYLE':
             for (let styleAttr in value) {
                 if (value.hasOwnProperty(styleAttr)) {
                     newElement['style'][styleAttr] = value[styleAttr];
                 }
             }
             break;
         case 'CHILDREN':
             /*
              * 可能是一個值:可能是字串也可能是一個JSX物件
              * 可能是一個陣列:陣列中的每一項可能是字串也可能是JSX物件
              */
             //->首先把一個值也變為陣列,這樣後期統一運算元組即可
             !(value instanceof Array) ? value = [value] : null;
             value.forEach((item, index) => {
                 //->驗證ITEM是什麼型別的:如果是字串就是建立文字節點,如果是物件,我們需要再次執行RENDER方法,把建立的元素放到最開始建立的大盒子中
                 if (typeof item === 'string') {
                     let text = document.createTextNode(item);
                     newElement.appendChild(text);
                 } else {
                     render(item, newElement);
                 }
             });
             break;
         default:
             newElement.setAttribute(attr, value);
     }
 }
 container.appendChild(newElement);
 callBack && callBack();
}

export {
 createElement,
 render
};

複製程式碼

相關文章