虚拟 DOM 只是一个 JS 的 Object 对象而已。它是虚拟的,需要用JS转成真实Dom对象。
虚拟DOM有什么优点
-
减少DOM操作
1.虚拟DOM可以将多次操作合并为一次操作。
2.虚拟DOM借助DOM diff 可以将多余的操作省略
-
跨平台
虚拟DOM不仅可以变成DOM,还可以变成小程序、iOS应用,因为虚拟DOM本质是JS对象
复制粘贴到HTML则可实现、亲测有效
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>virtualDom</title>
</head>
<body>
<div id="app"></div>
<script>
/**
* 创建元素
* @param type 类型
* @param props 参数
* @param children 子节点 = 数组 || 文字
*/
class Element {
constructor(type, props, children) {
this.type = type;
this.props = props;
this.children = children;
}
}
// 创建元素
function createElement(type, props, children) {
return new Element(type, props, children);
}
// 虚拟Dom
const vDOM = createElement('ul',
{
class: 'list',
style: 'width: 300px; height: 300px; background-color: orange'
},
[
createElement('li',
{class: 'item', 'data-index': 0},
[
createElement('p', {class: 'text'}, ['第1个选项'])
]),
createElement('li',
{class: 'item', 'data-index': 1},
[
createElement('p', {class: 'text'}, [
createElement('span', {
class: 'text'
}, [
'第2个列表选项'
])
])
]
),
createElement('li',
{class: 'item', 'data-index': 2},
['第3个列表选项']
)
]
);
/**
* 渲染函数虚拟DOM成真实的节点
* @method render
* @param vDOM 虚拟dom对象
* @return 返回真实的节点
*/
const render = (vDOM) => {
// 解析赋值 取出类型、参数和子节点
const {type, props, children} = vDOM;
// 获得根节点、并且把之后虚拟type转成节点
const el = document.createElement(type);
// 遍历属性
Object.keys(props).forEach(key => {
// 设置节点的属性和值
setAttrs(el, key, props[key]);
});
children.map(child => {
// 如果通过Element生成接着渲染?
// 是: 虚拟节点转元素
// 否: 创建文本节点
child = child instanceof Element
? render(child)
: document.createTextNode(child);
// 全部添加到每一级父元素、直到最顶级节点
el.appendChild(child);
});
return el;
};
/***
* 节点挂上属性
* @method setAttrs
* @param element 节点
* @param property 属性
* @param value 属性后的值
*/
function setAttrs(element, property, value) {
switch (property) {
// 或许是输入框
case 'value':
// 目前没测试value属性
if (element.tagName === 'INPUT' || element.tagName === 'TEXTART') {
// 输入框的值是value不是innerText
element.value = value;
} else {
element.setAttribute(property, value);
}
break;
// 如果是样式
case 'style':
element.style.cssText = value;
break;
// 默认情况就设置属性和值就好(不够严谨
default:
element.setAttribute(property, value);
break;
}
}
const realElement = render(vDOM);
// 获取到App元素
const App = document.querySelector('#app');
// 蹬蹬蹬~虚拟DOM转真实DOM成功
App.appendChild(realElement);
</script>
</body>
</html>