可以使用渐进式的方式去理解如果使用vdom渲染dom
创建div节点,创建text节点,然后挂载到根节点root上去
const dom = document.createElement('div')
dom.id = 'app'
document.getElementById('root').append(dom)
const textNode = document.createTextNode('')
textNode.nodeValue = 'hello world'
dom.append(textNode)
因为react也好,vue也罢,都是基于vdom去渲染真实dom的,所以我们可以模拟使用Vdom的方式去创建dom节点
// 创建一个text的vdom
const textEl = {
type: 'TEXT_ELEMENT',
props: {
nodeValue: 'hello world',
children: []
}
}
// 创建一个div的vdom
const el = {
type: 'div',
props: {
id: 'app',
children: []
}
}
// 执行挂载
const dom = document.createElement(el.type)
dom.id = el.props.id
document.getElementById('root').append(dom)
const textNode = document.createTextNode('')
textNode.nodeValue = textEl.props.nodeValue
dom.append(textNode)
从step2中我们模拟了一个vdom去生成真实dom,但显然这样的vdom相当于是写死的
所以我们可以改成动态创建的方式去迭代一下
// 动态创建text vdom
const createTextEl = (text) => {
return {
type: 'TEXT_ELEMENT',
props: {
nodeValue: text,
children: []
}
}
}
// 动态创建其他的 vdom
const createElement = (type, props, ...children) => {
return {
type,
props: {
...props,
children
}
}
}
// 生成vdom
const el = createElement('div', {id: 'app'})
const textEl = createTextEl('hello world')
// 执行挂载操作
const dom = document.createElement(el.type)
dom.id = el.props.id
document.getElementById('root').append(dom)
const textNode = document.createTextNode('')
textNode.nodeValue = textEl.props.nodeValue
dom.append(textNode)
vdom可以动态生成,但是挂载操作还是相当于写死的
所以我们可以通过写一个render函数来让他动态渲染
const createTextEl = (text) => {
return {
type: 'TEXT_ELEMENT',
props: {
nodeValue: text,
children: []
}
}
}
const createElement = (type, props, ...children) => {
return {
type,
props: {
...props,
children
}
}
}
/**
* 动态渲染vdom
* @param {*} app: vdom
* @param {*} container: 父节点
*/
function render(app, container){
// 1.创建dom节点
const dom = app.type === 'TEXT_ELEMENT'
? document.createTextNode('')
: document.createElement(app.type)
// 2.添加props
Object.keys(app.props).forEach(key => {
if(key !== 'children'){
dom[key] = app.props[key]
}
});
// 3.递归渲染子节点
app.props.children.forEach(child => {
render(child, dom)
})
// 4.添加到父节点中渲染
container.append(dom)
}
// 使用
const textEl = createTextEl('hello world')
const app = createElement('div', {id: 'app'}, textEl)
render(app, document.getElementById('root'))