if (typeof type === 'string') {
dom = document.createElement(type);
}
+ if (typeof type === 'function'){
+ // 让type执行,返回虚拟DOM,继续处理返回的虚拟DOM
+ return createDom(type(props));
+ }
if (props) {
我们的函数组件也可以正常渲染出来了.
对于类组件
我们先看一下原版的类组件
import React from 'react';
import ReactDOM from 'react-dom';
class Hello extends React.Component{
render(){
return <h1>hello <span>{this.props.name}</span></h1>
}
}
console.log('element', <Hello name="world" />);
ReactDOM.render(
<Hello name='world' />, document.getElementById('root')
);
在上步我们已经生成了虚拟DOM,接下来我们就要将这个虚拟DOM渲染到真实的DOM节点上面去,这个过程就是我们调用的
ReactDOM.render
这个函数.它接收一个虚拟DOM,以及一个真实的DOM节点,最终将这个虚拟DOM挂载到这个真实的DOM节点上面.
节点的渲染
对于这个虚拟DOM,我们知道它可能会是一个文本节点,也可能是一个HTML节点,以及我们常用的函数组件和类组件类型.所以对于虚拟DOM的处理我们要分几种情况来考虑.
当它不是一个React element时
它不是一个react element,即它不是通过
React.createElement
创建出来的一个对象,它是一个简单的值,也就是说当上面render函数里面的element
是值是一个string
,number
,null
,undefined
这些值的时候,它也是可以正常不渲染的,所以我们先来处理这种情况.它的真实DOM就是一个普通的文本节点.新建一个
ReactDOM/index
文件,我们创建一个render
函数来挂载真实DOM,以及一个createDOM
函数来生成真实的DOM节点.修改
src/index
文件,确实它可以正常渲染普通的HTML元素
当虚拟DOM是一个普通的HTML元素时,我们知道它有一个
type
属性来表示它的类型,比如h1
,div
,p
这些.这些我们就调用原生的Document.createElement
来创建真实DOM节点.对于createDom
函数增加一个类型判断来试试渲染我们最初的hello world!看看.
函数式组件
对于一个函数式组件
我们可以看到,打印出来的type是一个
function
,并且在props
上面包含了我们传递的参数我们知道,在函数组件里面,我们最终要return一个组件回来的,所以处理函数式组件也就也就很简单了,我们执行这个函数式组件,去获取到它的返回结果,就获取到了我们要渲染的虚拟DOM.
于是,继续扩展
createDom
这个函数我们的函数组件也可以正常渲染出来了.
对于类组件
我们先看一下原版的类组件
看一下它创建出来的虚拟长成什么样子
首先,它的
type
就是我们的class
,并且类组件是继承于React.Component
的,顺着原型链,我们可以找到一个isReactComponent
这个属性,它用来标识这是一个React组件.所以,首先我们要实际一个Component
这样一个父类.新建
src/react/Component.js
并在
src/react/index.js
中导入导出和函数组件返回一个虚拟DOM一样,在类组件里面,我们始终会调用
render
这个函数来返回一个虚拟DOM,所以,我们同样执行这个类组件来返回虚拟DOM即可.继续扩展
createDom
方法现在,我们的类组件也可以正常渲染出来了.
HTML元素attribute属性的处理
目前,我们只是把节点渲染出来了,但对于标签上面的属性还没有进行任何处理,比如要渲染一个组件
我们是没有处理上面的
id
,className
,style
这些属性的.其实这些属性我们也是调用js原生的方法来添加上去,只是对于style
要特殊一些,因为它传入的是一个对象,而我们用js赋值的时候使用的是dom.style.key=value
这样的形式.在
createDom
里面增加一句并且来实现这个方法
在
public/index.html
增加一段style
样式查看一下效果,我们的
id
,class
,style
都已经生效了.