react虛擬dom淺析

//說明
/**
 * ReactDOM.render(
 *  <h1>Hello, world!</h1>,
 *  document.getElementById('root')
 * );
 * babel轉譯之後
 * ReactDOM.render(React.createElement("h1", null, "Hello, world!"), 
 * document.getElementById('root'));
 * 所以首先需要一個函數createElement來轉寫html標籤語法(JSX)
 * 然後需要一個render函數掛載到dom裏
 */
let React = (function(){
    class Component{
        static isReactComponent = true;//區分是函數還是類的標識(class通過babel轉譯後也是函數)
        constructor(props){
            this.props = props;
        }
    }
    function ReactElement(type,props){
        const element = {type,props}
        return element;
    }
    function createElement(type,config,children){
        let propsName;
        const props = {};
        for(propName in config){
            props[propName] = config[propName];
        }
        const childrenLength = arguments.length - 2;
        if(childrenLength ==1){
            props.children = children;
        }else if(childrenLength>1){
            props.children = Array.from(arguments).slice(2);
        }
        return ReactElement(type,props);
    }
    return {
        createElement,Component
    }
})()
let ReactDom = (function(){
    function render(element,parentNode){
        if(typeof element == 'string' || typeof element == 'number'){
            return parentNode.appendChild(document.createTextNode(element));
        }
        let {type,props} = element;
        if(type.isReactComponent){
            let returnElement =new type(props).render();
            type = returnElement.type;
            props = returnElement.props;
        }else if(typeof type == 'function'){
            let returnElement = type(props);
            type = returnElement.type;
            props = returnElement.props;
        }
        
        let domElement = document.createElement(type);
        for(let propName in props){
            if(propName == 'className'){
                domElement.className = props[propName];
            }else if(propName == 'style'){
                let styleObj = props[propName];
                for(let attr in styleObj){
                    domElement.style[attr] = styleObj[attr];
                }
            }else if(propName == 'children'){
                let children = Array.isArray(props.children)?props.children:[props.children];
                children.forEach(child=>render(child,domElement));
            }else{
                domElement.setAttribute(propName,props[propName])
            }
        }
        parentNode.appendChild(domElement)
    }
    return {
        render
    }
})()
//普通使用
let element = React.createElement('h1',{
    className:'title',
    style:{
        color:'red',
        fontSize:'50px'
    }
},"hello",React.createElement("span",null,"常規寫法"));
ReactDom.render(element,document.getElementById('root'));

//函數組件調用
function welcome1(props){
    return React.createElement("h1",{id:'welcome'},props.name,props.age)
}

let element1 = React.createElement(welcome1,{name:'函數',age:'10'})
ReactDom.render(element1,document.getElementById('root'))

//類組件調用
class Welcome2 extends React.Component{
    render(){
    return React.createElement("h1",{id:'welcome'},this.props.name,this.props.age)
    }
}

let element2 = React.createElement(Welcome2,{name:'類',age:'10'})
ReactDom.render(element2,document.getElementById('root'))

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章