Virtual Dom原理浅析

       React开发人员敦促你在编写组件时使用一种称为JSX的语法,混合了HTMLJavaScript。但浏览器对JSX及其语法毫无头绪,浏览器只能理解纯碎的JavaScript,所以JSX必须转换成JavaScript。这里是一个divJSX代码,它有一个class name和一些内容:

<div className='cn'>
  Content!
</div>

以上的代码,被转换成正经JavaScript代码,其实是一个带有一些参数的函数调用:

React.createElement(
  'div',
  { className: 'cn' },
  'Content!'
);

让我们仔细看看这些参数。

  • 第一个是元素的type。对于HTML标签,它将是一个带有标签名称的字符串。
  • 第二个参数是一个包含所有元素属性(attributes)的对象。如果没有,它也可以是空的对象。
  • 剩下的参数都可以认为是元素的子元素(children)。元素中的文本也算作一个child,是个字符串’Content作为函数调用的第三个参数放置。

你应该可以想象,当我们有更多的children时会发生什么:

<div className='cn'>
  Content 1!
  <br />
  Content 2!
</div>
React.createElement(
  'div',
  { className: 'cn' },
  'Content 1!',              // 1st child
  React.createElement('br'), // 2nd child
  'Content 2!'               // 3rd child
)

把组件(components)组合成页面(page)

所以,我们已经将所有JSX组件转换为纯JavaScript,现在我们有一大堆函数调用,它的参数会被其他函数调用的,或者还有更多的其他函数调用这些参数这些带参数的函数调用,是怎么转化成组成这个页面的实体DOM的呢?为此,我们有一个ReactDOM库及其它的render方法:

function Table({ rows }) { /* ... */ } // defining a component

// rendering a component
ReactDOM.render(
  React.createElement(Table, { rows: rows }), // "creating" a component
  document.getElementById('#root') // inserting it on a page
);

ReactDOM.render被调用时,React.createElement最终也会被调用,返回以下对象:

// There are more fields, but these are most important to us
{
  type: Table,
  props: {
    rows: rows
  },
  // ...
}

这些对象,在React的角度上,构成了虚拟DOM

他们将在所有进一步的渲染中相互比较,并最终转化为 真正的DOMvirtual VS real, 虚拟DOM VS 真实DOM)。

下面是另一个例子:这次div有一个class属性和几个children

React.createElement(
  'div',
  { className: 'cn' },
  'Content 1!',
  'Content 2!',
);

变成:

扫描二维码关注公众号,回复: 4190966 查看本文章
{
  type: 'div',
  props: {
    className: 'cn',
    children: [
      'Content 1!',
      'Content 2!'
    ]
  }
}

 

需要注意的是,那些除了typeattribute以外的属性,原本是单独传进来的,转换之后,会作为在props.children以一个数组的形式打包存在。也就是说,无论children是作为数组还是参数列表传递都没关系 —— 在生成的虚拟DOM对象的时候,它们最后都会被打包在一起的。

进一步说,我们可以直接在组件中把children作为一项属性传进去,结果还是一样的:

<div className='cn' children={['Content 1!', 'Content 2!']} />

在构建虚拟DOM对象完成之后,ReactDOM.render将会按下面的原则,尝试将其转换为浏览器可以识别和展示的DOM节点:

  • 如果type包含一个带有String类型的标签名称(tag name—— 创建一个标签,附带上props下所有attributes
  • 如果type是一个函数(function)或者类(class),调用它,并对结果递归地重复这个过程。
  • 如果props下有children属性 —— 在父节点下,针对每个child重复以上过程。

最后,得到以下HTML(对于我们的表格示例):

	<table>
	  <tr>
	    <td>Title</td>
       </tr>
	  ...
	</table>

猜你喜欢

转载自blog.csdn.net/cao_dan/article/details/83108727