前言
上一篇文章讲了怎样在react中创建出虚拟dom,这一篇讲的是将虚拟dom转换为真实dom,
并在页面中渲染出来
怎样实现
说白了,render方法本质上就是将vdom对象中的属性值通过js语法生成对应的html标签,
然后将标签通过appendChild方法挂载到页面已经声明好的元素上面
代码实现
首先我们来看一下上一篇我们定义的createElement方法生成的vdom对象和render方法
{
$$typeof: Symbol(react.element),
key: null,
props: {
children: {type: Symbol("react.TEXT"), content: 'zhangsan'},
className: "title",
style: {color: '#fff'},
},
type: "h3",
ref: null,
}
ReactDOM.render(
element, // vdom
document.getElementById('root')
)
接下来,我们就来用代码来实现他,先来定义一个方法
function render (vdom, container) {
// 1. 将 vdom 转换为 真实dom
let newDOM = createDOM(vdom)
// 2. 将真实dom放到对应的位置
container.appendChild(newDOM)
}
第一步很好理解,我们接下来主要实现的就是createDOM 这个函数
function createDOM (vdom) {
// vdom => 真实dom
let { type, props } = vdom
let dom;
// 判断 type
/*
这一个判断是 我们在标签中props.children的时候会重新调用createDOM方法
这时vdom为{type: Symbol("react.TEXT"), content: 'zhangsan'}这样的结构
*/
if (type === Symbol("react.TEXT")) { // 文本
dom = document.createTextNode(vdom.content)
} else { // 元素
// 第一次type为标签 div,直接创建出来
dom = document.createElement(type)
}
// 最后将我们生成的真实dom返回出来
return dom
}
通过现在的代码我们可以生成一个标签,下面我们只需要在标签内填充内容即可
function createDOM (vdom) {
// vdom => 真实dom
let { type, props } = vdom
let dom;
// 1. 判断 type
if (type === Symbol("react.TEXT")) {
dom = document.createTextNode(vdom.content)
} else {
dom = document.createElement(type)
}
// 2. 处理属性
if (props) {
// 这个函数用来为标签添加 style key等属性
updateProps(dom, props)
// 3. 添加 children
let children = props.children
if (children) {
// 这个函数用来填充文本内容
changeChildren(children, dom)
}
}
// 最后将我们生成的真实dom返回出来
return dom
}
首先来实现 updateProps 函数
// 更新属性
function updateProps (dom, newProps) {
if (newProps) {
for (let key in newProps) {
// children属性 我们这里不需要处理,跳过
if (key === 'children') {
continue
} else if (key === 'style') { // 为标签添加样式
let styleObject = newProps[key]
for (let styKey in styleObject) {
// 为dom添加样式
dom.style[styKey] = styleObject[styKey]
}
} else { // 其他属性
dom[key] = newProps[key]
}
}
}
}
接下来就是 changeChildren 方法
// 处理children
function changeChildren (children, dom) {
// 一个children {}
if (typeof children === 'object' && children.type) {
// 这里传入的children 结构为{type: Symbol("react.TEXT"), content: 'zhangsan'}
// 这里再重新调用createDOM方法,就会进行文本的渲染
createDOM(children, dom)
} else if (Array.isArray(children)) { // 多个为数组 [{}, {}]
children.forEach(item => createDOM(item, dom))
}
}
至此,我们的 render 方法就定义好啦,去调用一下
render(
React.createElement("h3", { style: { color: 'blue' } }, "hello"),
document.getElementById('root')
)
这里就是今天的内容了,感谢观看