Vue source code analysis: rendering articles

This article was written by the author in May 2017. It has been almost a year, and it is well written. Please read more. We are also using vue2.0 now, and we can deeply understand how vue renders pages, rendering process and principles from the source code.

Reprinted from https://blog.csdn.net/generon/article/details/72482844

I. Introduction

  1. The Vue.js framework is one of the most popular MVVM frameworks at present. The simple and easy-to-use learning curve, friendly official documentation, and supporting construction tools make Vue.js shine in 2016, and it has a tendency to catch up with React. Not long ago, the official version of Vue.js 2.0 has been released, and it has improved in terms of volume optimization (50% reduction compared to 1.0), performance improvement (60% improvement compared to 1.0), and API optimization;

  2. This article is a series of articles, mainly through the analysis of the source code of Vue.js 2.0, to analyze the implementation principle of Vue.js from the code level, so as to help readers to understand the idea of ​​the whole framework more deeply. This article mainly introduces the front-end rendering part;

  3. Please criticize and correct the shortcomings, and welcome to exchange and learn together.

Second, the initialization of Vue

When we use Vue.js, the most basic use is to introduce the library file of Vue.js in HTML, and write the following code:

1.var app = new Vue({
2.  el: '#app',
3.  data: {
4.    message: 'Hello Vue!'
5.  }
6.})

The essence of new Vue is to generate a Vue object. Let's take a look at the process of generating a Vue object:

First, the entry of Vue is /src/entries/web-runtime-with-compiler.js, which is determined by the config.js configuration file.

image description

There are many files imported in this entry file, among which there is a main context:

/src/entries/web-runtime-with-compiler.js 
cited /src/entries/web-runtime.js 
cited cited /src/core/index.js 
cited/src/core/instance/index.js

Among them /src/core/instance/index.jsis the core initialization code, which:

image description

The red box part is the core method of the entire Vue class. Let the reader interpret its meaning:

1.//初始化的入口,各种初始化工作
2.initMixin(Vue) 
3.//数据绑定的核心方法,包括常用的$watch方法
4.stateMixin(Vue)
5.//事件的核心方法,包括常用的$on,$off,$emit方法
6.eventsMixin(Vue)
7.//生命周期的核心方法
8.lifecycleMixin(Vue)
9.//渲染的核心方法,用来生成render函数以及VNode
10.renderMixin(Vue)

Among them, new Vue executes the following function:

image description

_initThe method is the _initmethod in initMixin.

image description

至此,程序沿着这个_init方法继续走下去。

三、Vue的渲染逻辑——Render函数

在定义完成Vue对象的初始化工作之后,本文主要是讲渲染部分,那么我们接上面的逻辑,看Vue.js是如何渲染页面的。在上图中我们看到有一个initRender的方法:

image description

在该方法中会执行红框部分的内容:

image description

$mount方法就是整个渲染过程的起始点。具体定义是在/src/entries/web-runtime-with-compiler.js中,根据代码整理成流程图:

image description

由此图可以看到,在渲染过程中,提供了三种渲染模式,自定义Render函数、template、el均可以渲染页面,也就是对应我们使用Vue时,三种写法:

1. 自定义Render函数

1.Vue.component('anchored-heading', {
2.    render: function (createElement) {
3.        return createElement(
4.            'h' + this.level,   // tag name 标签名称
5.            this.$slots.default // 子组件中的阵列
6.        )
7.    },
8.    props: {
9.        level: {
10.            type: Number,
11.            required: true
12.        }
13.    }
14.})

2. template写法

1.var vm = new Vue({
2.    data: {
3.        // 以一个空值声明 `msg`
4.        msg: ''
5.    },
6.    template: '<div>{{msg}}</div>'
7.})

3. el写法(这个就是入门时最基本的写法)

1.var app = new Vue({
2.    el: '#app',
3.    data: {
4.        message: 'Hello Vue!'
5.    }
6.})

这三种渲染模式最终都是要得到Render函数。只不过用户自定义的Render函数省去了程序分析的过程,等同于处理过的Render函数,而普通的template或者el只是字符串,需要解析成AST,再将AST转化为Render函数。

记住一点,无论哪种方法,都要得到Render函数。

我们在使用过程中具体要使用哪种调用方式,要根据具体的需求来。

  • 如果是比较简单的逻辑,使用template和el比较好,因为这两种都属于声明式渲染,对用户理解比较容易,但灵活性比较差,因为最终生成的Render函数是由程序通过AST解析优化得到的;

  • 而使用自定义Render函数相当于人已经将逻辑翻译给程序,能够胜任复杂的逻辑,灵活性高,但对于用户的理解相对差点。

四、Vue的渲染逻辑——VNode对象&patch方法

根据上面的结论,我们无论怎么渲染,最终会得到Render函数,而Render函数的作用是什么呢?我们看到在/src/core/instance/lifecycle.js中有这么一段代码:

1.vm._watcher = new Watcher(vm, () => {
2.    vm._update(vm._render(), hydrating)
3.}, noop);

意思就是,通过Watcher的绑定,每当数据发生变化时,执行_update的方法,此时会先执行vm._render(),在这个vm._render()中,我们的Render函数会执行,而得到VNode对象。

image description

VNode对象是什么?VNode就是Vue.js 2.0中的Virtual DOM,在Vue.js 2.0中,相较Vue.js 1.0引入了Virtual DOM的概念,这也是Vue.js 2.0性能提升的一大关键。Virtual DOM有多种实现方式,但基本思路都是一样的,分为两步:

1. Javascript模拟DOM模型树

在Vue.js 2.0中Javascript模拟DOM模型树就是VNode,Render函数执行后都会返回VNode对象,为下一步操作做准备。在/src/core/vdom/vnode.js中,我们可以看到VNode的具体数据结构:

image description

VNode的数据结构中还有VNodeData、VNodeDirective、VNodeComponentOptions,这些数据结构都是对DOM节点的一些描述,本文不一一介绍。读者可以根据源码来理解这些数据结构。(PS:Vue.js使用了flow,标识了参数的静态类型,对理解代码很有帮助^_^)

2. DOM模型树通过DOM Diff算法查找差异,将差异转为真正DOM节点

我们知道Render函数执行生成了VNode,而VNode只是Virtual DOM,我们还需要通过DOM Diff之后,来生成真正的DOM节点。在Vue.js 2.0中,是通过/src/core/vdom/patch.js中的patch(oldVnode, vnode ,hydrating)方法来完成的。

该方法有三个参数oldVnode表示旧VNode,vnode表示新VNode,hydrating表示是否直接使用服务端渲染的DOM元素,这个本文不作讨论,在服务端渲染篇再详细介绍。

The main logic is that when the VNode is a real element or the old VNode and the new VNode are exactly the same, the createElm method is directly called to generate a real DOM tree. When there is a difference between the old and the new VNode, the patchVnode method is called. Different states add, delete, and modify the DOM reasonably (readers interested in the Diff algorithm here can read the patchVnode method by themselves, which will not be repeated because of the space), and then call createElm to generate the real DOM tree.

Five, Vue rendering summary

Looking back, the rendering logic here is not particularly complicated, and the core key steps are still very clear:

  1. new Vue, perform initialization
  2. Mounting $mountmethod, generate Render function by customizing Render method, template, el, etc.
  3. Monitor data changes through Watcher
  4. When the data changes, the Render function executes to generate the VNode object
  5. Through the patch method, compare the old and new VNode objects, and through the DOM Diff algorithm, add, modify, and delete real DOM elements

At this point, the rendering process of the entire new Vue is completed. Vue rendering principle

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324692077&siteId=291194637