ReactDOM.render的渲染原理

ReactDOM.render的渲染原理

在react项目中,之所以可以在函数/组件中直接写模板结构,是因为最后babel都会帮我们把这些模板转译成 React.createElemen(config) 的形式,这也就是为什么我们在每一个组件中明明没有主动调用React,但是却要引入react的原因。

// 举例
import React from 'react';
import ReactDOM from 'react-dom';

let h = React.createElement(
  'div',{className:'box',style:{fontSize:'30px', color:'green'}},'第一个儿子',
  React.createElement('h2',{style:{color:'red',textAlign: 'center'}},'第二个儿子')
  );

let p = <div className='box' style={{fontSize:'30px', color:'green'}}>
  第一个儿子
  <h2 style={{color:'red',textAlign: 'center'}}>第二个儿子</h2>
</div>
ReactDOM.render(<>
   {h}
   {p}
  </>,
document.getElementById('root'));
// p和h渲染的页面是一样的

渲染结果:
渲染结果
简单实现 React.createElement 和 ReactDOM.render 的功能

let React = {
  createElement(type, attr, ...children) {
    // type 是对应的标签名
    // attr 是标签内的一些行内属性
    // children 是type标签元素的后代元素
    let el = document.createElement(type);
    return new Element(type, attr, children);
  }
}

let ReactDOM = {
  render(ele, container) {
    container.appendChild(ele.render());
  }
}

function Element(el, attr, children) {
  this.el = el;
  this.attr = attr;
  this.children = children;
}
Element.prototype = {
  constructor: Element,
  render() {
    // 负责把虚拟DOM变成真实的DOM
    let el = document.createElement(this.el);
    // 把行内属性放到el中
    let keys = Object.keys(this.attr);
    for (let i = 0; i < keys.length; i++) {
      let key = keys[i];
      // 不能直接放,需要对特殊的行内属性进行处理
      switch (key) {
        case 'className':
          el.setAttribute('class', this.attr[key]);
          break;
        case 'htmlFor':
          el.setAttribute('for', this.attr[key]);
          break;
        case 'style':
          let str = '';
          Object.keys(this.attr[key]).forEach(item=>{
            str += `${this.changeStyle(item)}: ${this.attr[key][item]};`
          })
          el.setAttribute('style', str);
          break;
        default:
          el.setAttribute(key, this.attr[key]);
      }
    }
    this.children.forEach(item => {
      // item 可能是一个字符串,也有可能是一个虚拟DOM
      // 如果是字符串,则之间插入文本节点;如果是虚拟DOM,则需要先转为真实DOM再插入到el中
      let text;
      if (typeof item === 'string') {
         text = document.createTextNode(item);
      } else {
        text = item.render();
      }
      el.appendChild(text);
    });
    return el;
  },
  changeStyle(str) {
    // 正则匹配:把属性中的驼峰命名转变成串式命名:例如 fontSize -> font-size
    return str.replace(/[A-Z]/g, b => {
      return '-' + b.toLowerCase();
    }).replace(/^-/, '');
  }
}

let h2 = React.createElement('div', {
    className: 'h1box',
    style: {
      fontSize: '30px',
    }
  },
  '呵呵呵', // 和Vue不同,react的这里是如果有多个子元素,就直接往后接着写(Vue是多个子元素就用数组包起来)
  React.createElement('h2', {
    className: 'h2',
    style: {
      color: 'red'
    }
  }, '哈哈哈')
)

ReactDOM.render(h2, document.getElementById('root'))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值