浅显易懂地介绍Vue2运行时渲染系统

232 阅读5分钟

当我们在使用Vue2的响应式来操作DOM时,不禁会想到 Vue2 的响应式系统是如此强大和方便,它可以让我们通过修改数据对象的属性,自动更新视图,而不必手动操作 DOM。其声明式的架构不仅保留了声明式的可维护性、还保留了一个较好的性能、对我们的心智负担也是相当友好的。要想实现这样一个强大的框架,必然就要有一个优秀的DOM渲染系统,这就是我们今天要介绍的主题。

运行时

在 Vue2 中,运行时通常指Vue2 应用程序会根据组件的配置信息和用户传入的数据动态生成虚拟 DOM,并通过一定的算法将其转换为真实 DOM 并渲染到页面中。我们这里要讨论的就是运行时的vue2渲染系统。

核心函数

在我们窥探渲染系统的全貌时,我们需要了解其四个函数

Vue2 的渲染系统的核心函数是 render()、h()、updateComponent() 和 patch()。

h函数

这是vue2中createElement函数的别名。

h()主要用于创建虚拟DOM,它是一个工具函数,也就是用于创建虚拟DOM的工具。

它接收三个参数:

一、标签名tagName

二、一个用于描述属性的对象

三、子节点。 可以是文本节点,也可以是h函数创造的节点

//一个简单的h函数示例
h("div",
    {
    class:"container"
    innerText:"hello vue2"
    },
    [
    h("p",{innerText:"nihao"}),
    ])

这样我们就创造了一个div,它的class是container,它的inneText是"hello vue2",它有一个子节点P,P的innerText是"nihao。

h 函数的返回值是一个虚拟节点(Virtual Node),也称为 VNode。虚拟节点是一个 JavaScript 对象,用于描述真实 DOM 节点的结构和属性。

render函数

Vue 在生成虚拟 DOM 树时也会使用 render 函数。在 Vue 的运行时模式下,我们通常需要使用 render 函数来生成组件的虚拟 DOM 树。

render 函数接收一个 createElement 函数作为参数,该函数可以用来创建虚拟节点,也就是 h 函数。createElement 函数的别名是 h 函数,所以在 render 函数中也可以使用 h 函数来创建虚拟节点。

render 函数的返回值是一个虚拟节点(Virtual Node),也称为 VNode。

//一个简单的示例:
render: function (h) {
  return h("div", { innerText: "Hello, Vue2!" })
}

patch函数

patch 函数是 Vue2 渲染系统中非常重要的一部分,它用于将虚拟 DOM 树转换为真实 DOM 树,并将其渲染到浏览器中。

我们熟悉的diff算法就运行在patch函数中。patch函数有三个参数:

一、旧的虚拟 DOM 树

二、新的虚拟 DOM 树

三、用于挂载真实 DOM 的容器元素

熟悉diff算法的朋友们应该一眼就能知道patch函数的作用了。patch 函数会比较旧的虚拟 DOM 树和新的虚拟 DOM 树的差异,然后将差异转换为最少的 DOM 操作。并将更新应用到真实 DOM 上,从而实现视图的更新。

updateComponent函数

当页面数据发生变化时,会先通知Dep,再让Dep通知Watcher,并调用Watcher中的updateComponent函数来实现页面的渲染。

关于Dep和Watcher可以查看我之前的文章。

updateComponent 一般是挂载在 Watcher 实例中,用于实现数据的响应式更新和视图的渲染。updateComponent的主要功能是先后调用render和patch函数,也就是先生成虚拟DOM,再进行diff算法的比较,最后实现真实DOM的挂载。

updateComponent 函数的核心代码

function updateComponent() {
  // 执行渲染函数生成新的虚拟 DOM 树
  const vnode = vm._render();
​
  // 通过 patch 函数将新的虚拟 DOM 树与旧的虚拟 DOM 树进行对比,并将更新应用到真实 DOM 上
  vm._update(vnode);
}

全面理解四者的关系

我们可以通过一个比喻来了解四者的关系:

可以把 render 函数比作是一个建筑设计师,负责设计建筑的蓝图,而 h 函数则是建筑设计师的工具箱,提供了各种可以用来设计建筑的工具和材料。当建筑设计师完成了蓝图设计之后,updateComponent 函数就像是一个建筑监理,负责在施工过程中监督并协调各个工人的工作,确保建筑按照设计蓝图进行施工。最后,patch 函数就像是建筑工人,根据蓝图和监理的指示,把建筑材料组装起来,建造出一栋实际的建筑。

在这个比喻中,render和h提供了用于构建虚拟 DOM 树方法。

patch负责进行diff算法的运算,将新的虚拟 DOM 树和旧的虚拟 DOM 树进行比较,最终把差异更新到实际的 DOM 树上。

updateComponent()负责在数据变化时触发调用其他三个方法来完成页面渲染

总结

最后我们通过一个简单的逻辑线来了解响应式系统与渲染系统之间的联系。

页面数据变化 → 通知 Dep → 通知相应的 Watcher 实例 → 执行 updateComponent 函数 → 调用 render 函数生成新的虚拟 DOM 树 → 调用 patch 函数进行比较 → 更新页面。

本文用于记录自己的学习,欢迎指出错误。