React的Render的简单实现

createElement然后遍历children属性,完成整个dom的创建,其实是相当耗费性能的,react之所以能实现高性能,是因为它实现了局部dom的更新,而不是像我们_render方法里面那么简单粗暴。 更新优化算法diff

ReactDOM.render(
    <h1>Hello, world!</h1>,
    document.getElementById('root')
);

实际上是JSX进过转换是这样的

ReactDOM.render(
    React.createElement( 'h1', null, 'Hello, world!' ),
    document.getElementById('root')
);

render方法的作用就是将对象转换成虚拟DOM,再最终渲染成真实的DOM

function render( vnode, container ) {
    
    // 当vnode为字符串时,渲染结果是一段文本 // 1. 判断节点类型
    if ( typeof vnode === 'string' ) {
        const textNode = document.createTextNode( vnode );
        return container.appendChild( textNode ); // 2. 给真实节点返回该类型的节点
    }
​
    const dom = document.createElement( vnode.tag );  // 3. 获取要创建节点的标签名
​
    if ( vnode.attrs ) { // 4. 判断是否有attr属性,有则遍历attr属性给每个设置属性
        Object.keys( vnode.attrs ).forEach( key => {
            const value = vnode.attrs[ key ];
             setAttribute( dom, key, value );    // 设置属性
        } );
    }
​
    vnode.children.forEach( child => render( child, dom ) );    // 5. 递归渲染子节点
​
    return container.appendChild( dom );    // 6. 将渲染结果挂载到真正的DOM上
}

还有setAttribute方法:

function setAttribute( dom, name, value ) {
    // 如果属性名是className,则改回class
    if ( name === 'className' ) name = 'class';
​
    // 如果属性名是onXXX,则是一个事件监听方法
    if ( /on\w+/.test( name ) ) {
        name = name.toLowerCase();
        dom[ name ] = value || '';
    // 如果属性名是style,则更新style对象
    } else if ( name === 'style' ) {
        if ( !value || typeof value === 'string' ) {
            dom.style.cssText = value || '';
        } else if ( value && typeof value === 'object' ) {
            for ( let name in value ) {
                // 可以通过style={ width: 20 }这种形式来设置样式,可以省略掉单位px
                dom.style[ name ] = typeof value[ name ] === 'number' ? value[ name ] + 'px' : value[ name ];
            }
        }
    // 普通属性则直接更新属性
    } else {
        if ( name in dom ) {
            dom[ name ] = value || '';
        }
        if ( value ) {
            dom.setAttribute( name, value );
        } else {
            dom.removeAttribute( name );
        }
    }
}

每次render前,清理一下之前的内容:

const ReactDOM = {
    render: ( vnode, container ) => {
        container.innerHTML = '';
        return render( vnode, container );
    }
}

在index.html里面增加容器:<div id="root"></div>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值