vue的执行过程都发生了什么

前言

vue执行过程内部都发生了什么,什么是模板解析,为什么能做到响应式更新视图?以下为大家介绍下一个vue项目执行的一个大致流程。(这里讲的是一个大致流程,vue真实的实现比这里说的复杂多,但本文主要是为你介绍大致的实现思路,加深你对vue的理解)

首先我们来看下这个流程的总体步骤:
在这里插入图片描述
然后我们根据这四个步骤来一 一介绍

一、 模板解析为 render 函数

首先,什么是模板?模板就是那些html标签,包括嵌入到html标签里面的指令和变量 v-if=“isShow”。在vue看来它们都是一堆字符串,需要先解析它们,并由此生成一个 render函数,render函数就是用来创建虚拟DOM的(vdom),举个栗子
假如模板为

	<div id="app">
	    <p> {{ price }} </p>
	</div>

那么生成的render函数内容为
在这里插入图片描述
这里面的this指向的是vue实例,使用with是方便书写,里面需要用到data的属性时可以直接写变量名,不需要类似这样:vm.price;
_c( )函数返回的是一个 vnode(虚拟节点,也就是描述DOM的js对象,对虚拟DOM不了解的建议先去了解下),第一个参数是标签名,第二是属性(没有属性可省略),第三是子节点数组;
_v( )函数返回的是一个描述文本节点的虚拟节点;
_s( )函数类似于toString返回一个字符串。

由于这个render函数内部是由一个 _c( )函数包裹着,所以,render函数执行结果返回的是一个 虚拟节点 vnode。注意这一步只是生成了render函数,并没有调用!!而且解析模板这一步在使用打包工具的时候,就已经由打包工具生成好了render函数。然后进入下一步

记住,包括v-if,v-for等等这些逻辑处理都已经存在于render中了,而这些指令最终有什么效果都取决于赋给它的变量,所以最终还是data中的数据起着关键作用,所以说vue是数据驱动着视图,我们只需要关心数据层

这是这一步的流程
在这里插入图片描述

二、 响应开始监听

当程序开始执行的时候,我们知道会先实例一个Vue对象,

	var vm = new Vue({ options });

options里面包含了data属性,我们要用到的属性值也都是写在这个data里面。此时vue需要将我们在data里面声明的属性绑定到自己身上,也就是vm身上。

这里就用到了关键函数:Object.defineProperty( obj, name, {...} );
这个函数可以为一个对象添加属性,并可以在这个属性被访问或被赋值时执行我们添加的逻辑代码。了解了这个函数之后,你就大致知道为什么我们修改data的中的属性,视图也会跟着修改了。

我们来简单模拟下vue把data中属性通过defineProperty添加到自己身上

	class Vue {
		constructor(options){
		    this.$el = options.el;
		    // 模拟 vue内部绑定属性
		    let data = options.data();
		    for (const key in data) {
		        if (data.hasOwnProperty(key)) {
		            Object.defineProperty(this, key, {
		                get(){
		                    console.log('get:监听处理逻辑代码');
		                    return data[key];
		                },
		                set(newValue){
		                    data[key] = newValue;
		                    console.log('set:调用更新模板视图的函数,完成响应式');
		                }
		            })
		        }
		    }
		}
	}
	//实例化
	var vm = new Vue({
	    el: '#app',
	    data () {
	        return {
	            price: 100
	        }
	    }
	})

执行完这一步后,vue实例就拥有了data中的属性,我们可以直接用 vm.price访问到,并且访问或者赋值这些属性时都会执行我们添加的逻辑代码,至于vue在里面添加了什么代码继续往下看

执行完这一步,我们在第一步生成的render函数才可以执行,还记得吗,上面的render函数中引用了price变量,而且是通过 vm.price访问的。所以只有执行完第二步,vm上面才有price这个变量

三 、渲染页面,绑定依赖

执行完前两步,我们已经有了render函数和属性,开始来渲染页面了。(如果对 vdom-虚拟DOM不太了解的话,可以先去看下snabbdom,了解下渲染vdom的几个关键函数,因为这里vue内部处理vdom与snabbdom核心相似)

首先,vue中有一个函数,专门来管理渲染页面,叫updateComponent();updateComponent函数类似于这样:
在这里插入图片描述
其中 vm._render( )就是我们前面获得的render函数,执行返回的是一个vnode,把vnode传入vm._update( )中去,并利用关键函数 __patch__( )对虚拟DOM生成真正的DOM,渲染到页面(同样,如果你了解snabbdom,那么这里你很容易就能看懂。)

这里vm._update( )有两种情况:
第一种是首次渲染,就直接将vnode一次性渲染到vm.$el根节点里面去;
第二种就不是第一次渲染已经有视图了,而是需要更新视图。然后传入 __patch__( )函数的是两个vnode,第一个是旧的vnode,第二个是render函数重新执行返回的最新vnode,然后__patch__( )会同过 diff 算法比较出两份vnode的差异,然后仅修改那些差异来更新视图,大大提升了性能。
具体流程
在这里插入图片描述
这个时候页面已经显示出来了,接下来就是显示实时监听了

四、 监听data属性变化

vue是由数据驱动视图更新的,而这里的数据就是data里面的属性。

例如,当我们通过点击按钮修改其中一个属性的值时,就会触发该属性的 set函数,(还记得在第二步我们为vm绑定属性时,为每个属性设置了getset方法吗),为了做到视图响应式更新,那么我们只要在set函数里面加入更新视图的函数 updateComponent ( ) 就可以了(vue的具体实现会比这复杂多,但我们这里主要为了学习它的思路)。

那么按照我们所说的,在set里面加入updateComponent ( ),那么属性被修改时,触发updateComponent ( )vm.render( )重新执行,获得最新的vnode,传入vm._update( ),通过__patch__( )函数比较新老vnode的差异,并更新视图,这就完成了响应式。
在这里插入图片描述

到了这里基本就是vue实现的大致思路,但是你可能有个疑惑?监听属性变化并响应式更新到视图去好像只需要监听set就行,没有关get啥事哩?

那我们可不可以只监听set就行?

答案当然是不可以咯,这里有些细节没介绍到。就是我们的data中有很多属性,可能有些属性我们在程序中根本就没用到,而有用到的属性都会触发get方法,所以没有触发过get方法的属性,那我们也无需要关心它的set。这样,就算改变它的值,也不会调用更新视图的函数 updateComponent ( ),所以就避免了不必要的重复渲染。
下面关于这个疑惑给张图:
在这里插入图片描述

希望看完的你能对vue的实现有一个大致的认识

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值