这是我参与更文挑战的第 12 天,活动详情查看: 更文挑战
2021-06-12 前端框架 虚拟DOM DIFF基础
Diff算法(一),聚焦前端面试
1. 虚拟DOM
因为diff算法是发生在虚拟DOM上面的,因此先说一说什么是虚拟DOM
1.1 基本概念
简单来说就是用一个对象去描述一个真实的DOM结构,例如:
<div class="box">
<h1>DOM</h1>
<ul>
<li>真实DOM</li>
<li>虚拟DOM</li>
</ul>
</div>
复制代码
{
sel:'div',
data:{
class:'box'
},
child:[
{sel:'h1', data:{}, text:'DOM'},
{
sel:'ul',
data:{},
child:[
{sel:'li', data:{}, text:'真实DOM'},
{sel:'li', data:{}, text:'虚拟DOM'}
]
}
]
}
复制代码
1.2 虚拟DOM的基本属性
一般一个虚拟DOM需要如下的基本属性:
- sel:表示描述的节点的sel是什么
- data:这个节点必要属性值
- elm:表示这个虚拟dom的真实dom节点,如果是undefined,表示这个虚拟dom没有上树(patch)
- key:表示这个节点的唯一标识
- text:标识的是文本
1.3 什么是patch(上树)
其实就是将虚拟dom渲染到真实dom树上去,这个过程叫patch(上树)
2. h函数(产生虚拟节点)
在vue文档中render部分其实有讲,这里简单的说一下
2.1 h函数基本使用
h函数是用来产生虚拟DOM节点的(VNode),例如:
h(a,{props:{ href:'http://www.baidu.com'}},'百度一下')
就会得到如下的虚拟节点
{
sel:'a',
data:{
href:'http://www.baidu.com'
},
text:'百度一下'
}
复制代码
表示的真实节点为:
<a href="http://www.baidu.com">百度一下</a>
2.2 手写简单的h函数
- 第一步就是写一个VNnode函数,经过上面的分析,这个函数其实就是返回一个对象
function VNode(sel,data,children,text,elm){
return {
sel,
data,
children,
text,
elm
}
}
复制代码
- 编写h函数前,我们要想明白一个事,就是简易版的h函数接受三个参数,有以下三个状态
h('div',{},'文本')
h('div',{},[...])
h('div',{},h(...))
于是有代码如下:
/**
* @param { String } sel 虚拟dom标签
* @param { Object } data 虚拟dom属性
* @param { 可以是虚拟dom,文本,[]} c
* @return VNode
* Vnode 返回有三个形态
* 1. h('div',{},'文本')
* 2. h('div',{},[...])
* 3. h('div',{},h())
**/
function h(sel,data,c){
if( Array.from(arguments).length !==3 ){
throw new Error('参数错误,请检查')
}
if(typeof c === 'string' || typeof c === 'number'){
return VNode(sel,data,undefined,c,undefined)
}
if( Array.isArray(c) ){
const children = c.map((item)=>{
if(!(typeof item === 'object' && item.hasOwnProperty('sel'))){
throw new Error('传入的数组元素成员不是h()函数返回的虚拟dom')
}else{
return item
}
})
return VNode(sel,data,children,undefined,undefined)
}
if(typeof c === 'object' && c.hasOwnProperty('sel')){
return VNode(sel,data,[c])
}
return new Error('参数错误,请检查')
}
// 测试用例
console.log( h('div',{},'前端好难啊') )
console.log( h('div',{},[
h('div',{},'要学底层'),
h('div',{},'要学框架'),
h('div',{},'要学英语')
]) )
console.log( h('div',{},h('div',{},'生命不息,内卷不止')) )
复制代码
接下来请关注第二部分
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END