最近在看一些源码学习文章,今晚上等发版有空就记录一下吧。
1、什么是虚拟DOM
已经9102年了,前端er或多或少都接触过一些mvvm库,了解有虚拟DOM这么个东西,可能你还没有深入了解过这个东西,其实很简单,来往下看。
虚拟DOM简而言之就是,用JS去按照DOM结构来实现的树形结构对象,也就是一个JS对象而已。
2、什么样的对象才能比较匹配的上dom结构呢
来看一下如下图所示的dom结构
上图是比较简单的一个结构,比较理想的是使用如下对象来模拟:
{
// 节点类型
type: 'ul',
// 节点的属性,包括dom原生属性和自定义属性
props: {
class: 'list',
style: 'color:red;'
},
// 子节点数组
// 子对象结构也是一样,包含了type,props,children,没有子节点的话就是普通文本
// 子对象拥有子节点时,继续往下扩展就行
children: [
{type: 'li',props: {class: 'list'},children: ['利群']},
{type: 'li',props: {class: 'list'},children: ['玉溪']},
{type: 'li',props: {class: 'list'},children: ['黄鹤楼']}
]
}
OK,对象结构已经解析完成
3、批量创建这个对象---终于可以上代码了
// 定义一个构造函数来
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);
}
let virtualDom = createElement('ul',{class:'list',style:'color:red;'},[
createElement('li',{class:'item'},['利群']),
createElement('li',{class:'item'},['玉溪']),
createElement('li',{class:'item'},['黄鹤楼']),
]);
// 对象形势的结构展示
console.log(virtualDom);
OK,查看打印出来的对象是这样的
4、将虚拟的DOM对象渲染成真实的DOM,添加两个方法
// 把虚拟对象转成dom对象
function render(domObj) {
// 根据元素类型来创建dom
let el = document.createElement(domObj.type);
// 遍历props对象,然后给创建的元素el设置属性
for (let key in domObj.props) {
// 设置属性的方法
setAttr(el, key, domObj.props[key]);
}
// 遍历子节点数组
domObj.children.forEach(child = >{
// 需要注意的是:如果child是虚拟dom,就继续递归渲染
if (child instanceof Element) {
child = render(child);
} else {
// 只是普通的文本内容
child = document.createTextNode(child);
}
// 把子节点添加到父节点中
el.appendChild(child);
});
return el;
}
// 上面用到的设置属性
function setAttr(node, key, value) {
// 需要判断key是什么
switch (key) {
case 'value':
// 属性是value就要看标签类型了,input和textarea的value就需要做区别
if (node.tagName.toLowerCase() === 'input' || node.tagName.toLowerCase() == 'textarea') {
node.value = value;
} else {
node.setAttribute(key, value);
}
break;
case 'style':
node.style.cssText = value;
break;
default:
node.setAttribute(key, value);
break;
}
}
// 将元素插入页面
function renderDom(el, target) {
target.appendChild(el);
}
// 定义一个构造函数来
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);
}
// 调用之前的createElement方法
let virtualDom = createElement('ul',{class:'list',style:'color:red;'},[
createElement('li',{class:'item'},['利群']),
createElement('li',{class:'item'},['玉溪']),
createElement('li',{class:'item'},['黄鹤楼']),
]);
// 对象形势的结构展示
console.log(virtualDom);
// 渲染dom
let el = render(virtualDom); // 得到dom元素
console.log(el);
renderDom(el,document.querySelector('body'));
OK,结果如下:
写的并不是很清晰,需要一行一行看下来啦...eemme,有待提升,我改bug去了。