You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
React 中没有数据响应式机制,数据更新后框架不知道具体哪里要做修改,而整个组件全部 DOM 重渲染性能又过差。于是提出了 Virtual DOM 概念,将真实 DOM 结构做一层抽象。数据更新时,React 对前后 Virtual DOM 树进行 Diff(创建 Virtual DOM 树成本可比创建真实 DOM 低的多!),准确找出要修改的部分,进行最小化的真实 DOM 修改,提升性能。
然而 Vue 1.0 就实现了数据响应式机制,数据修改时能准确做到『指哪打哪』,只修改关联的 DOM,为什么在 2.0 中也拥抱了 Virtual DOM 呢?加了这样一个中间层必然有成本,带来了什么好处?
HTML 模板的高度抽象。受限于 html 语法限制,我们难以复用 HTML 节点;而使用 Virtual DOM,我们能够用 JS 描述 DOM 节点,从而带来了复用 HTML 模板的能力,提高效率。
<divclass="container"><!-- test --><buttonv-on:click="clickHandler">click me</button><ul:class="testClass" v-if="show"><liv-for="city in arr" >{{city}}</li></ul></div>
对 Virtual DOM 根节点调用 createDOM 方法之后,就获得的真实 DOM appendChild 即可。
2.4 Diff 算法
Vue 中的 Virtual DOM 算法是基于 snabbdom 的一个轻量实现。diff 只在同层级之间进行比较,网上解读 diff 的文章已经足够多了,这里限于篇幅也不再贴出代码,diff 核心代码 100 行左右即可搞定,有兴趣可以看我自己实现的版本。由于 Virtual DOM 对应的真实 DOM 节点已经挂在自己的 elm 属性下面,边遍历就可以边进行真实 DOM 的修改。
title: 现代前端科技解析 —— Virtual DOM
categories:
tags:
toc: true
date: 2019-03-07 11:20:10
本文解析 Virtual DOM 在框架中的实际运用:如何构建一个 Virtual DOM,并基于其构建真实 DOM。当 Virtual DOM 结构发生改变时,如何进行 Diff,并更新真实 DOM。
1. Virtual DOM 概述
Virtual DOM 是一个 JavaScript 数据结构,可以描述真实 DOM 的组织结构。
React 中没有数据响应式机制,数据更新后框架不知道具体哪里要做修改,而整个组件全部 DOM 重渲染性能又过差。于是提出了 Virtual DOM 概念,将真实 DOM 结构做一层抽象。数据更新时,React 对前后 Virtual DOM 树进行 Diff(创建 Virtual DOM 树成本可比创建真实 DOM 低的多!),准确找出要修改的部分,进行最小化的真实 DOM 修改,提升性能。
然而 Vue 1.0 就实现了数据响应式机制,数据修改时能准确做到『指哪打哪』,只修改关联的 DOM,为什么在 2.0 中也拥抱了 Virtual DOM 呢?加了这样一个中间层必然有成本,带来了什么好处?
2. Virtual DOM 实现
2.1 Virtual DOM 数据结构
本文实现的 Virtual DOM 参考 Vue,结构简化,如下:
2.2 Virtual DOM 生成
Virtual DOM 从何而来?前一篇文章所讲的现代前端科技解析 —— HTML Parser 可以将 template 解析为 AST。但是 AST 中只是模板占位符,还需要结合真实数据才是最终结果。于是 Vue 将 template 解析成 AST 后,又将其转换为 render() 函数。将数据传参进去,生成实时的 Virtual DOM。
2.2.1 compileToFunction
如何将 AST 转换成 render 函数呢?我们看一个 jsx 转换的例子:
转换前:
转换后:
简单来看,我们就是把每个 ASTElement 都替换成一个
createElement
函数。函数接收参数,返回 vdom 结果。我们首先实现几个 vdom 创建函数:随后使用
new Function
生成 render 函数。具体思路就是递归,对每个 ASTElement 进行转换,转换为_c()
这种创建 vdom 的函数调用。如果不了解 ASTElement 这个数据结构先读一下前文现代前端科技解析 —— HTML Parser哦。此处加入了一些对
v-if
,v-for
等指令的处理。理解起来比较容易,对于v-if
的 dom,转换为三元表达式;对于v-for
的 dom,转换为一个 map 函数。实例:
转换前:
转换后:
这样就完成了 render 函数的转换。如果对 Vue 中更详实的
compileToFunctions
函数感兴趣,可以查阅源码中的 CodeGen 部分。2.3 创建真实 DOM
执行编译好的 render 函数,就可以获得 Virtual DOM。基于 Virtual DOM 生成真实 DOM,不难,主要还是深度遍历。核心代码:
对 Virtual DOM 根节点调用 createDOM 方法之后,就获得的真实 DOM appendChild 即可。
2.4 Diff 算法
Vue 中的 Virtual DOM 算法是基于 snabbdom 的一个轻量实现。diff 只在同层级之间进行比较,网上解读 diff 的文章已经足够多了,这里限于篇幅也不再贴出代码,diff 核心代码 100 行左右即可搞定,有兴趣可以看我自己实现的版本。由于 Virtual DOM 对应的真实 DOM 节点已经挂在自己的 elm 属性下面,边遍历就可以边进行真实 DOM 的修改。
diff 思路如下:
几种常见情况的 diff 过程:
Vue 中的 diff 源码可见 patch 部分,思路是一致的。
3.参考资料
The text was updated successfully, but these errors were encountered: