1.什么是虚拟DOM
我们在前端面试的时候,经常会被问到什么是虚拟DOM
。这个概念,感觉很熟悉,但又说不出它到底是什么。现在我们来探索一下到底什么是虚拟DOM
。
首先我们看下什么是DOM
,对于DOM
,我们应该都很熟悉了,下面是MDN对于DOM
的定义
文档对象模型 (DOM) 将 web 页面与到脚本或编程语言连接起来。通常是指 JavaScript,但将 HTML、SVG 或 XML 文档建模为对象并不是 JavaScript 语言的一部分。DOM模型用一个逻辑树来表示一个文档,树的每个分支的终点都是一个节点(node),每个节点都包含着对象(objects)。DOM的方法(methods)让你可以用特定方式操作这个树,用这些方法你可以改变文档的结构、样式或者内容。节点可以关联上事件处理器,一旦某一事件被触发了,那些事件处理器就会被执行。
虚拟DOM
自然就是跟DOM
有很大关系的了。我们在使用原生JS开发或者使用Jquery开发,经常就会操作DOM
,但是我们使用的时候发现,每次我们改变DOM
的时候,页面再次渲染,会花费不短的一段时间,这样用户体验就不太好了。如果我们每次操作的不是DOM
或者每次只操作更少的DOM
呢,是不是会花费的时间更短呢,基于这个想法,就有了虚拟DOM
。
在React中,会把DOM
转换成JavaScript对象
,然后再把JavaScript对象
转化成DOM
,这样我们对于DOM
的操作,实际上是在操作这个JavaScript对象
。
2.DOM是如何创建虚拟DOM的
我们利用在线babel工具来看下。左边是JSX,右边是JSX经过babel转换后的效果,事实上JSX是右边这种写法的语法糖,我们在React项目中写的JSX的写法都会转换成右边这种写法。
在React项目中,使用以下这种写法,渲染出的效果也是一样的。
import React from 'react';
import ReactDOM from 'react-dom';
let element = React.createElement("h1", {
id: "test",
className: "testClass"
}, "test");
ReactDOM.render(element, document.getElementById('root'));
现在我们来分析以下上面的代码
React.createElement()
方法传入了3个参数,第1个参数对应的是标签名称,第2个参数是属性,第三个参数是内容,然后返回某个值ReactDOM.render()
方法接收了两个参数,第一个参数是刚刚提到的某个值,第二个参数是获取到的root元素,对应的是index.html
中的<div id="root"></div>
在上面的代码中加入console.log(element)
,打印出element
的值,然后看到,原来某个值是这样的:
由此说明:React.createElement()
方法创建了虚拟DOM
。
3.模拟实现React.createElement()
有上图可以这个对象有多个属性,目前来说对我们比较重要的是props
和type
属性,所以先实现对于这两个属性的操作。
React.createElement()
接收3个参数,现在要把这3个参数合并到type
和props
中。
React.createElement()
接收3个以上参数,说明该元素里面有多个子元素(这些子元素仍然是React.createElement()
),那么把第二个参数后面的所有参数转换成数组放入children
中
function ReactElement(type, props) {
const element = { type, props };
return element;
}
function createElement(type, config = {}, children) {
let propName;
const props = {}; // 定义props
for(propName in config) {
props[propName] = config[propName]; // 复制config的属性到props中
}
// 处理children
const childrenLength = arguments.length - 2;
if(childrenLength === 1) {
props.children = children;
} else {
// 有多个子元素的情况
props.children = Array.from(arguments).slice(2);
}
return ReactElement(type, props);
}
加入以下代码测试下效果
const element = createElement("h1", {
id: "test",
className: "testClass"
}, createElement("span", null, "span1"), createElement("span", null, "span2"));
console.log(JSON.stringify(element))
打印结果为:
可以看到,最终,DOM转换成了JavaScript对象
。