vue源码阅读—02—数据驱动


 

数据驱动还有的疑问:


2.render函数如何产生vnode?
在core/vdom/render函数里有vm_render方法,调用这个方法就会调用我们自己定义的render函数,然后通过我们传递的h函数其实是vm.$creatElement方法;
然后在vm.$creatElement方法根据不同的情况,new 不同的Vnode类得到不同的vnode实例即可;


3.如果optoins里没有el?
optons没有el,那必须有new Vue().mount(el),否则会报错,因为根本不知道挂载在哪

4.options里没有render也米有template可以吗?
当然可以。首先会去判断有没有render,有render直接去吧render转化为vnode;
其次,如果咩有render,会把template通过complier模块转化为render,再转化为vnode;
最后,如果没有render没有template,那么把el所代表的html当作template,转化为render再转化为vnode;
不过建立在我们使用compiler+runtime版本,才会把el转化为render;
如果我们使用的是runtime-only版本,那么会报错,因为没有什么东西可以把el转化为render;而在lifetcycle.js的mountComponent阶段,必须要有render函数,否则报错;

 

 

vue是数据驱动的,我们使用vue可以减少对dom的操作,只需要修改数据,vue会自动帮助我们修改dom;

 

this._c和this._init这些都是私有变量和私有方法,只能Vue函数内部使用,我们new出来的vue实例不应该在外部去调用它们这些方法;

this.$foo这个变量前面加上$表示,这个变量是Vue定义到vm实例上的,和我们自己定义到vm实例上的变量有所区别,这个变量是公有的,我们在自己new出来的vue实例也可以使用;;

数据驱动:

传递一个js对象,如何映射到dom上的:

 

  

 

 

 

 

 

一、vdom是什么?

Virtual DOM 就是用一个原生的 JS 对象去描述一个浏览器的 DOM 节点。

二、VDOM 为什么比真实 DOM性能开销小? 

「Virtual Dom 的优势」其实这道题目面试官更想听到的答案不是上来就说「直接操作/频繁操作 DOM 的性能差」,如果 DOM 操作的性能如此不堪,那么 jQuery 也不至于活到今天。所以面试官更想听到 VDOM 想解决的问题以及为什么频繁的 DOM 操作会性能差。

首先我们需要知道:

1、DOM 引擎、JS 引擎 相互独立,但又工作在同一线程(主线程) JS 代码调用 DOM API 必须 挂起 JS 引擎、转换传入参数数据、激活 DOM 引擎,DOM 重绘后再转换可能有的返回值,最后激活 JS 引擎并继续执行。所以直接一次dom操作比较耗时;

2若有频繁的 DOM API 调用,且浏览器厂商不做“批量处理”优化, 引擎间切换的单位代价将迅速积累。

3若其中有强制重绘的 DOM API 调用,重新计算布局、重新绘制图像会引起更大的性能消耗。

其次,我们要知道vdom:

  1. vdom并没有操作dom的方法,所以vdom是非常轻量的;
  2. vdom用js来描述,js的创建和修改相对真实dom都是非常快速的,所以vdom的性能比较高;虚拟 DOM 不会立马进行排版与重绘操作,会在最后批量处理,有利于减少引擎切换的代价;
  3. 虚拟 DOM 进行频繁修改,然后一次性比较并修改真实 DOM 中需要改的部分(diff算法),最后在真实 DOM 中进行排版与重绘,减少过多DOM节点排版与重绘损耗。

总结:1.vdom是js描述的处理起来非常快速  2:批处理,减少引擎切换的代价  3.diff算法,尽量减少修改;

VDOM 比真实 DOM的优点? 

1.绝大部分情况下,性能开销小;除少数所有dom全部都要变化的情况下,这个时候由于vdom还要做diff算法,所以可能性能开销反而会更大;

2.由于是js来描述真实dom,所以是可以跨平台的;

 

 

三、vdom怎么产生?

在 Vue.js 中,Virtual DOM 是用 VNode 这么一个 Class 去描述,它是定义在 src/core/vdom/vnode.js 中的。所以,vode就是vdom,

那vnode怎么产生的呢?

在vue的render函数中,通过createElelment方法也即是h函数产生vnode。

四、vdom到真实dom的过程

Virtual DOM 除了它的数据结构的定义,映射到真实的 DOM 实际上要经历 VNode 的 create、diff、patch 等过程。

通过vnode的create、diff、patch过程,就可以了;

 

 

 

_update 方法的作用?

把 VNode 渲染成真实的 DOM,它的定义在 src/core/instance/lifecycle.js 中:

Vue 的 _update 是实例的一个私有方法,它被调用的时机有 2 个,一个是首次渲染,一个是数据更新的时候

 

 

 

 

 

new Vue:

1.调用this_Init

2.调$mount($el)

3.如果是runtime-compiler版本,先调自己的mount方法,在这个方法里将template转化为render,再调用通用的mount方法;

如果是runtime-only版本,这种版本一般是工程化的,.vue文件的template会被vue-loader转化为render好了,所以直接调用通过mount方法;

4.通用的mount方法,

   4.1确保存在render函数,调用beforeMounted钩子函数;

   4.2调用mountComponent方法,这个方法做了两个操作

  • 定义一个函数updateComponnet = ()=》{vm._update(vm._render())}
  • new 了一个渲染watcher并将updateComponent赋值给watcher的getter,并调用getter

5.

   5.1vm._render去实例化vnode节点

   5.2vm._update将vnode节点调用patch操作,第一步将根据vnode的tag创建真实dom;第二步先把本vnode节点的子vnode节点通过node的insretBefore或appendChild插入到本vnode节点,再把自身vnode节点插入到真实dom上;第三步把挂载的div#app这个dom删除掉完成替换;

6.通过 invokeInsertHook()去callhook(vm, 'mounted);

7.结束;

 

 

 

 

组件对象有两个阶段:

第一个是创建即实例化init阶段;

第二个是挂载mount阶段;分为编译render函数、渲染阶段通过render函数实例化组件Vnode、patch阶段即将vnode映射到真实dom上;

 

 

组件对象、组件构造函数、组件实例、组件vnode实例;

1.组件对象是我们自定义的;

2.组件构造函数是在实例化子组件占位符vnode时,把子组件对象变成了一个继承vue的子组件构造函数;

3.组件实例:new 组件构造函数时,得到组件实例;组件实例有组件对象的所有配置项,通过vm.$options可以取到;然后vm实例还有很多属性和方法;

4.组件vnode:通过_render()渲染阶段,调用调用vm.$options.render函数,生成一个组件的vnode实例;

 

 

这个config.isReservedTAg方法被重写了。
因为在src/core/global-api/index.js中定义了Object.defineProperty(Vue, 'config', configDef)
然后在平台中,/src/platforms/web/runtime/index.js        Vue.config.isReservedTag = 平台重写的isReservedTag;
所以,我们访问Vue.config时,根据Object.defineProperty,访问的就是我们在core/config.js里的config;
所以,被重写;
 

 

 

 

 

为什么自己写的render函数h参数是vm.$createelemt,而编译器编译模板生成的redner函数用的是vm._c?

这个是我们使用vuejs的complier模块把模板编译成render函数的结果,我们看到,render变量引用地址所指向是一个匿名函数,并且这个匿名函数没有参数,所以在vm._render()中调用 vnode = render.call(vm._renderProxy, vm.$createElement)时即使传递了参数vm.$createElement也没有用,照样调用vm._c;

 

根节点如何渲染的?

渲染根节点的时候,会把  挂载的真实dom元素  作为第一个参数即oldVNode传给patch方法;

patch方法里,会通过emptyNodeAt方法把真实dom元素也生成vnode节点然后再重新赋值给oldVnode  (不过dom元素并没有消失,通oldvnode.elm即可获取)

patch的最后,会把老的el所代表的dom摧毁掉,然后挂载新的dom元素。

 

流程:

 

posted @ 2022-05-23 20:33  Eric-Shen  阅读(92)  评论(0编辑  收藏  举报