1. 搭建JSX环境, webpack.config.js
    • webpack4.x
    • yarn add babel-loader @babel/core @babel/preset-env —dev
      1. module.exports = {
      2. mode: 'development',
      3. entry: {
      4. main: './src/main.js'
      5. },
      6. module: {
      7. rules: [
      8. {
      9. test: /\.js$/,
      10. use: {
      11. loader: 'babel-loader',
      12. options: {
      13. presets: ['@babel/preset-env']
      14. }
      15. }
      16. }
      17. ]
      18. }
      19. }
    1. 实现JSX要求的create
    • yarn add @babel/plugin-transform-react-jsx —dev

    添加配置plugins: ['@babel/plugin-transform-react-jsx'] 后会自动解析<div></div>标签为React.createElement("div", null)
    修改配置 plugins: [['@babel/plugin-transform-react-jsx', {pragma: 'createElement'}]] , 编译后变为createElement("div", null)

    1. <div></div>
    2. createElement("div", null, "")
    3. <div>hello</div>
    4. createElement("div", null, "hello");
    5. <div id="app" class="head"></div>
    6. createElement("div", {
    7. id: "app",
    8. "class": "head"
    9. });
    10. function createElement(tagName) {
    11. return document.createElement(tagName)
    12. }
    • 第一个参数, tagName
    • 第二个参数,attributes, null、{}
    • 第三个参数, ‘text’文本, []子标签、文本
    1. 基本概念:attribute、children ```
      hello
      createElement(“div”, { id: “app”, “class”: “head” }, “hello”)

    function createElement(tagName, attributes, text) { let element = document.createElement(tagName) for (const key in attributes) { element.setAttribute(key, attributes[key]) } if (text) { let node = document.createTextNode(text) element.appendChild(node) } return element }

    1. 处理子标签

    createElement(“div”, { id: “app”, “class”: “head” }, createElement(“span”, null), createElement(“span”, null), createElement(“span”, null))

    function createElement(tagName, attributes, …rest) { let element = document.createElement(tagName) if (typeof attributes === ‘object’ && attributes instanceof Object) { // setAttribute } for(let child of rest) { if (typeof child == ‘string’) { child = document.createTextNode(child) } element.appendChild(child) } return element }

    1. 4. 处理自定义组件

    class Hello extends Component { render () { return

    {this.children}
    } }

    XXX render(window.a, document.body)

    1. 借助root属性。toy-react.js

    function render(component, parentElement) { parentElement.appendChild(component.root) } class Component { // 处理自定义组件 constructor() { this.props = Object.create(null); this.children = []; this._root = null; } // setAttribute(name, value) appendChild(component) { this.children.push(component) } get root() { if (!this._root) this._root = this.render().root return this._root } } class ElementWrapper { // 包裹标签 constructor(type) { this.root = document.createElement(type) } // setAttribute(name, value) appendChild(component) { this.root.appendChild(component.root) } } class TextWrapper { constructor(content) { this.root = document.createTextNode(content) } } // 循环处理子标签 let insertChildren = (children) => { for(const child of children) { if (typeof child == ‘string’) { child = new TextWrapper(child) } if ((typeof child == ‘object’) && (child instanceof Array)) { insertChildren(child) } else { element.appendChild(child) } } } insertChildren(rest) ```