index.js

  1. import React from "./react";
  2. // 渲染 字符串、 jsx、 类组件...
  3. class SubCounter {
  4. componentWillMount() {
  5. console.log("子组件将要挂载");
  6. }
  7. componentDidMount() {
  8. console.log("子组件已挂载✔");
  9. }
  10. render() {
  11. return "嘿嘿"
  12. }
  13. }
  14. class Counter extends React.Component {
  15. constructor(props) {
  16. super(props);
  17. this.state = {
  18. number: 1
  19. }
  20. }
  21. componentWillMount() {
  22. console.log("父组件将要挂载");
  23. }
  24. componentDidMount() {
  25. console.log("父组件已挂载✔");
  26. }
  27. render() {
  28. console.log('name:', this.props.name);
  29. // return this.state.number
  30. // return React.createElement(SubCounter, { name: 1 })
  31. return (
  32. <SubCounter />
  33. )
  34. /* return (<div className="container">
  35. <h1>
  36. <span>设备枚举示例</span>
  37. </h1>
  38. </div>) */
  39. }
  40. }
  41. /*
  42. React.createElement(Counter, {
  43. name: "xixi"
  44. });
  45. */
  46. /* function say() {
  47. alert(1)
  48. } */
  49. // let ele = <div>xiao</div>
  50. // let ele = React.createElement('div', {name: 'xixi' }, 'hello', React.createElement('button', {onclick: say }, '123'))
  51. // console.log('ele', ele);
  52. React.render(
  53. /* 'hello' */
  54. /* ele */
  55. /* <Counter name="xixi"></Counter> */
  56. React.createElement(Counter, {
  57. name: "xixi"
  58. }),
  59. document.getElementById('root')
  60. )

react

index.js

  1. import $ from 'jquery'
  2. import createReactUnit from "./unit.js";
  3. import createElement from './element'
  4. import Component from './component'
  5. let React = {
  6. render,
  7. createElement,
  8. Component,
  9. nextRootIndex: 0
  10. }
  11. function render(ele, container) {
  12. // 工厂函数处理不同的类型,创建并返回对应的react元素实例
  13. let createReactUnitInstance = createReactUnit(ele)
  14. let markUp = createReactUnitInstance.getMarkUp(React.nextRootIndex)
  15. // console.log("markUp===", markUp);
  16. // let markUp = `<span data-reactid=${React.nextRootIndex}>${ele}</span>`;
  17. $(container).html(markUp)
  18. // 触发 DOM挂载完成的方法
  19. $(document).trigger('mounted') // 所有组件都ok了
  20. }
  21. export default React;

util.js

  1. import $ from 'jquery'
  2. class Unit {
  3. constructor(ele) {
  4. // 通过父类保存参数
  5. this.curEle = ele
  6. }
  7. }
  8. // 渲染 文本 组件
  9. class ReactTextUnit extends Unit {
  10. getMarkUp(rootId) {
  11. this._rootId = rootId
  12. return `<span data-reactid=${rootId}>${this.curEle}</span>`;
  13. }
  14. }
  15. // 渲染 jsx 组件
  16. class ReactNativeUnit extends Unit {
  17. getMarkUp(rootId) {
  18. this._rootId = rootId
  19. let { type, props } = this.curEle;
  20. let tagStart = `<${type} data-reactid="${rootId}"`
  21. let tagEnd = `</${type}>`
  22. let contentStr = ''
  23. for (const propName in props) {
  24. if (propName.startsWith('on')) {
  25. let eventType = propName.slice(2).toLowerCase()
  26. // 事件委托
  27. $(document).on(eventType, `[data-reactid="${rootId}"]`, props[propName])
  28. } else if (propName === 'children') {
  29. contentStr = props[propName].map((child, idx) => {
  30. let childInstance = createReactUnit(child)
  31. return childInstance.getMarkUp(`${rootId}.${idx}`)
  32. }).join('')
  33. } else {
  34. tagStart += ` ${propName}="${props[propName]}"`
  35. }
  36. }
  37. return tagStart + '>' + contentStr + tagEnd
  38. }
  39. }
  40. // 渲染 类组件
  41. class ReactCompositUnit extends Unit {
  42. getMarkUp(rootId) {
  43. this._rootId = rootId
  44. let { type: Component, props } = this.curEle
  45. let componentInstance = new Component(props)
  46. // 创建实例后,即将挂载
  47. componentInstance.componentWillMount && componentInstance.componentWillMount()
  48. // 调用 render 后返回的结果
  49. let reactComponentRenderer = componentInstance.render()
  50. // 递归渲染 返回的结果 (先序深度优先, 递归树)
  51. let reactCompositUnit = createReactUnit(reactComponentRenderer)
  52. // console.log("reactCompositUnit", reactCompositUnit);
  53. let markUp = reactCompositUnit.getMarkUp(rootId)
  54. // console.log("markUp", markUp);
  55. // 深层组件先挂载完成,(在递归之后执行,由内而外)
  56. $(document).on('mounted', () => {
  57. componentInstance.componentDidMount && componentInstance.componentDidMount()
  58. })
  59. return markUp
  60. }
  61. }
  62. function createReactUnit(ele) {
  63. if (typeof ele === 'string' || typeof ele === 'number') {
  64. return new ReactTextUnit(ele)
  65. }
  66. if (typeof ele === 'object' && typeof ele.type === 'string') {
  67. return new ReactNativeUnit(ele)
  68. }
  69. if (typeof ele === 'object' && typeof ele.type == 'function') {
  70. return new ReactCompositUnit(ele)
  71. }
  72. }
  73. export default createReactUnit

element.js

image.png
image.png

  1. class Element {
  2. constructor(type, props) {
  3. this.type = type
  4. this.props = props
  5. }
  6. }
  7. function createElement(type, props, ...children) {
  8. props = props || {}
  9. props.children = children
  10. return new Element(type, props)
  11. }
  12. // 返回虚拟dom
  13. export default createElement

component.js

  1. class Component {
  2. constructor(props) {
  3. this.props = props
  4. }
  5. setState() {
  6. console.log("更新");
  7. }
  8. }
  9. export default Component

效果:
image.png