1.先使用createElement()方法生成虚拟dom节点
createElement(‘ul’, {class: ‘list’}, [
createElement(‘li’, {class: ‘item’}, [‘1’])
] )
1.1. 确定VNode的结构
class Element {
constructor(tagName, props, children) {
this.tagName = tagName
this.props = props
this.children = children
}
}
1.2. createElement - 创建一个节点的方法
/**
* 创建一个结点
* @param {*} type
* @param {*} props
* @param {*} children
*/
function createElement(type, props, children) {
return new Element(type, props, children);
}
2.使用render函数生成真实dom
function render(eleObj) {
let el = document.createElement(eleObj.type)
for ( let key in eleObj.props) {
// 设置属性的方法
setAttr(el, key, eleObj[props].key)
}
eleObj.children.forEach(child => {
child = (child instanceof Element) ? render(child) : document.createTextNode(child)
el.appendChild(child)
})
return el;
}
3.使用setAttribute方法给dom结点设置属性
function setAttr(node, key, value) {
swith(key) {
case ‘value’: // node是一个input或者textarea单独设置属性
if(node.targetName.toUpperCase() === ‘input’ || node.targetName.toUpperCase() === ‘textarea’) {
node.value = value;
} else {
node.setAttribute(key, value);
}
break;
case ‘style’ :
node.style.cssText = value;
break;
default:
node.setAttribute(key, value)
break
}
}
4.渲染函数,把生成的真实结点绑定到target根元素上
function renderDom(el, target) {
target.appendChild(render(el))
}
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
</div>
<script>
class Element {
constructor(tagName, props, children) {
this.tagName = tagName
this.props = props
this.children = children
}
}
/**
* 创建一个结点
* @param {*} type
* @param {*} props
* @param {*} children
*/
function createElement(type, props, children) {
return new Element(type, props, children);
}
/**
* 给结点设置properties
* @param {*} node
* @param {*} prop
* @param {*} value
*/
function setAttrs(node, prop, value) {
switch (prop) {
case 'value':
if (node.tagName == 'INPUT' || node.tagName === 'TEXTAREA') {
node.value = value;
} else {
node.setAttribute(prop, value);
}
break;
case 'style':
node.style.cssText = value;
break;
default:
node.setAttribute(prop, value);
break;
}
}
/**
* 将一个virtualdom转换成真实dom对象
* @param {*} vDom
*/
function render(vDom) {
const {
tagName,
props,
children
} = vDom
const el = document.createElement(tagName);
for (let key in props) {
setAttrs(el, key, props[key]);
}
children.map((c) => {
if (c instanceof Element) {
c = render(c);
} else {
c = document.createTextNode(c);
}
el.appendChild(c)
})
return el;
}
/**
* 将一个节点添加到root元素上
* @param {*} rDom
* @param {*} rootEl
*/
function renderDom(rDom, rootEl) {
rootEl.appendChild(rDom);
}
// 开始测试
const rootEl = document.getElementById("app")
const vDom = createElement(
'ul', {
class: 'list',
style: 'width:300px;height:300px;background-color:orange'
},
[
createElement(
'li', {
class: 'item',
data_id: 0,
},
[
createElement(
'p', {
class: 'text',
},
["第一个列表项"]
)
]
),
createElement(
'li', {
class: 'item',
data_id: 1,
},
[
createElement(
'p', {
class: 'text',
},
[
createElement(
'span', {
class: "title"
},
[
'第二个列表项'
]
)
]
)
]
),
createElement(
'li', {
class: "item",
data_id: 2
},
[
'第三个列表项'
]
)
]
)
trueDom = render(vDom)
renderDom(trueDom, rootEl)
</script>
</body>
</html>


843

被折叠的 条评论
为什么被折叠?



