# react_study **Repository Path**: aeipyuan/react_study ## Basic Information - **Project Name**: react_study - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-05-12 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 实现一个精简版React --- ## React.createElement 作用:将babel解析的结果转换成树形结构 ```javascript class Element { constructor(type, props) { this.type = type; this.props = props; } } function createElement(type, props, ...children) { props = props || {}; props.children = children; return new Element(type, props); } export default createElement ``` 转化前: ```javascript let element = React.createElement("h1", { class: "app", style: "color:red;font-size:100px;" }, "hello", React.createElement("button", null, "123")); ``` 转化后:  ## React.render 作用:渲染元素到对应位置 ```javascript /* react.js */ import $ from 'jquery' import createElement from './element' import createReactUnit from './unit'; import Component from './component' /* React对象 */ let React = { createElement, render, nextRootIndex: 0,/* 元素编号 */ Component } /* render负责将转化的element渲染到页面 */ function render(element, container) { /* 创建单元并编号 */ let createReactUnitInstance = createReactUnit(element); let markUp = createReactUnitInstance.getMarkUp(React.nextRootIndex); /* 渲染到容器上 */ $(container).html(markUp); /* 触发订阅函数 */ $(document).trigger('mounted'); } ``` #### createReactUnit createReactUnit函数负责将传入的格式化element分为三类分别处理(文本,原生元素,组件),另外创建一个父类,减少冗余代码 ```javascript import $ from 'jquery' /* 创建一个父类,放置多次重复写constructor */ class Unit { constructor(element) { this.currentElement = element; } } /* 文本单元 */ class ReactTextUnit extends Unit { getMarkUp(rootId) { //... } } /* 原生单元 */ class ReactNativeUnit extends Unit { getMarkUp(rootId) { //... } } /* 组件单元 */ class ReactComponent extends Unit { getMarkUp(rootId) { //... } } /* 根据不同类型生成不同单元 */ function createReactUnit(element) { /* 创建文本单元 */ if (typeof element === "string" || typeof element === "number") { return new ReactTextUnit(element); } /* 创建标签 */ if (typeof element === "object" && typeof element.type === "string") { return new ReactNativeUnit(element); } /* 组件 */ if (typeof element === "object" && typeof element.type === "function") { return new ReactComponent(element); } } export default createReactUnit ``` 1. 文本 直接在用`span`包围并记录`data-reactid` ```javascript class ReactTextUnit extends Unit { getMarkUp(rootId) { /* 存rootId */ this._rootId = rootId; /* 111 */ return `${this.currentElement}`; } } ``` 2. 原生标签 通过字符串拼接的方式连接属性,对于`children`,通过递归的方式创建子单元,用一个字符串`content`来存生成的标签字符串,对于`onClick`等事件绑定,使用`$(document).on()`绑定事件解决字符串无法绑定的问题 ```javascript class ReactNativeUnit extends Unit { getMarkUp(rootId) { this._rootId = rootId; /* 提取数据 */ let { type, props } = this.currentElement; /* 创建外围标签 */ let tagStart = `<${type} data-reactid=${rootId}`, tagEnd = `${type}>`; /* 遍历标签属性 */ let content = ""; for (let key in props) { /* 儿子结点 */ if (key === "children") { content += props[key].map((child, index) => { let childUnit = createReactUnit(child); return childUnit.getMarkUp(`${rootId}.${index}`) }).join(''); } /* {onClick:show} 事件 */ else if (/^on[A-Z]/.test(key)) { /* 绑定事件 */ let eventType = key.slice(2).toLowerCase(); $(document).on(eventType, `[data-reactid="${rootId}"]`, props[key]); } /* 普通属性 */ else tagStart += ` ${key}="${props[key]}" `; } /* 拼接返回 */ return `${tagStart}>${content}${tagEnd}`; } } ``` 传入element ```html (