初识react(一) 揭开jsx语法和虚拟DOM面纱

313 阅读2分钟

1、jsx简介 (js+xml)

看如下代码

const ele = <h1 className={"box"} style={{fontSize:"20px",color:"red"}}>hello</h1>

- jsx语法中用className代替html中class
- jsx中{}可以存放表达式(有返回值)
- style写法就如上面。放在对象中{color:'red'}
这段代码并不是合法的js代码,它是一种被称为jsx的语法扩展,通过它我们就可以很方便的在js代码中书写html片段。
本质上,jsx是语法糖,上面这段代码会被babel转换成如下代码



2、虚拟dom究竟是什么?(控制台打印下)


- 以上就是最简单虚拟DOM的样子,就是一个对象。

- 其中最主要关注的是的type(类型)、props(属性)我们关注的重点

- createElement()方法。 ->转变为虚拟DOM

-render()方法。 ->讲虚拟DOM转变真实DOM

3、createElement方法的实现

稍微把html结构写复杂点

let ele = (<div> <h1 style={{fontSize:'20px'}} className='box'>hello</h1> <h1 style={{fontSize:'20px'}} className='box'>world</h1></div>);

经过babel转换为

var ele = React.createElement( 
 'div', 
 null, 
 ' ', 
 React.createElement( 'h1', { style: { fontSize: '20px' }, className: 'box' }, 'hello' ), 
 React.createElement( 'h1', { style: { fontSize: '20px' }, className: 'box' }, 'hello' ) 
);


createElement方法实现

function createElement(type, props, ...childrens) {
    return {
        type:type, //类型,比如div
        props:{
            ...props,
            children:childrens.length<=1?childrens[0]:childrens //childrens长度不为1时,会进行递归解析
        }
    }
}


注意:{...null}会变成 {} ,并不会报错

{...null,name:'zs'},会变成{name:'zs'}


测试下效果


- createElement()转化为虚拟DOM还是比较简单的,下面来实现讲虚拟DOM转化为真实的DOM呢

4、render()方法的实现

function render(jsxObj, container) {
    //解构types和props解构props中的children
    let {type, props} = jsxObj, {children} = props;
    let newElement = document.createElement(type);//创建type类型的DOM元素
    for (let attr in props) { //循环props
        switch (attr) {
            case 'className': //attr为className,增加class="xxx"属性
                newElement.setAttribute('class', props[attr]);
                break;
            case 'style': //attr为styel,js实现增加样式
                let styleOBJ = props['style'];
                for (let key in styleOBJ) {
                    newElement['style'][key] = styleOBJ[key];
                }
                break;
            case 'children':
                let childrenAry = props['children'];
                //childrenAry为数组-> childrenAry,为str的话 ->[str] ,为空的话-> [].统一转变数组便于循环
                childrenAry = childrenAry instanceof Array ? childrenAry : (childrenAry ? [childrenAry] : []);
                childrenAry.forEach(item => {
                    if (typeof item === 'string') {
                        //文本节点,直接增加到元素中
                        newElement.appendChild(document.createTextNode(item));
                    } else {
                        //新的JSX元素,递归调用RENDER,只不过此时的容器是当前新创建的newElement
                        render(item, newElement);
                    }
                });
            default:
                newElement.setAttribute(attr, props[attr]);
        }
    }
    container.appendChild(newElement);
}

-写了很多注释,便于大家理解

-childrenAry可能是array or string or 空。我们统一都变成数组,便于后面我们遍历元素

-render方法主要是递归解析过程,根据虚拟dom不同的key,给真实的dom节点增加不同的属性

测试下