作者:小土豆biubiubiu
博客园:https://www.cnblogs.com/HouJiao/
掘金:https://juejin.im/user/58c61b4361ff4b005d9e894d
简书:https://www.jianshu.com/u/cb1c3884e6d5
微信公众号:土豆妈的碎碎念(扫码关注,一起吸猫,一起听故事,一起学习前端技术)
欢迎大家扫描微信二维码进入群聊讨论(若二维码失效可添加微信JEmbrace拉你进群):
码字不易,点赞鼓励哟~
本篇文章内容过长,一次看完会有些乏味,建议大家可以先收藏,分多次进行阅读,这样更好理解。
相信很多人和我一样,在刚开始了解和学习生命明周期的时候,会做下面一系列的总结和学习。
的实例在创建时会经过一系列的初始化:
在这个初始化的过程中会运行一些叫做"生命周期钩子"的函数:
关于每个钩子函数里组件的状态示例:
结合前面示例1的运行结果会有如下的总结。
组件创建前(beforeCreate)
组件创建完毕(created)
组件挂载前(beforeMount):
组件挂载完毕(mounted)
组件更新前(beforeUpdate)
组件更新完毕(updated)
组件销毁前(beforeDestroy)
组件销毁完毕(destroyed)
最后的总结,就是来自官网的生命周期图示。
那到这里,前期对生命周期的学习基本就足够了。那今天,我将带大家从了解,开启的进阶学习。
Vue官网的这张生命周期图示非常关键和实用,后面我们的学习和总结都会基于这个图示。
对于一个组件,框架要做的第一步就是创建一个实例:即。那都做了什么事情呢,我们来看一下构造函数的源码实现。
从的源码可以看到有两个重要的内容:和。那下面我们就这两个点进行抽丝破茧,看一看它们的源码实现。
在这里需要说明的是文件的引入会早于代码的执行,因此在之前会先执行、、、、。这些方法内部大致就是在为组件实例定义一些属性和实例方法,并且会为属性赋初值。
我不会详细去解读这几个方法内部的实现,因为本篇主要是分析学习的源码实现。那我在这里说明这个是想让大家大致了解一下和这部分相关的源码的执行顺序,因为在构造函数中调用的方法内部有很多实例属性的访问、赋值以及很多实例方法的调用,那这些实例属性和实例方法就是在引入的时候通过执行、、、、这几个方法定义的。
if条件判断逻辑如下:
我们先看一下前半段的逻辑。
是环境内置的一个,它提供有关当前进程的信息并对其进行控制。如果本机安装了环境,我们就可以直接在命令行输入一下这个全局变量。
这个全局变量包含的信息非常多,这里只截出了部分属性。
对于process的evn属性 它返回当前用户环境信息。但是这个信息不是直接访问就能获取到值,而是需要通过设置才能获取。
可以看到我没有设置这个属性,所以访问获得的结果是。
然后我们在看一下项目中的对的设置说明:
执行时会将设置为
执行时会将设置为
该配置在Vue项目根目录下的中设置
所以设置的作用就是为了区分当前项目的运行环境是还是,针对不同的环境在打包时会启用不同的。
前半段的逻辑说完了,在看下后半段的逻辑:。
这个逻辑我决定用一个示例来解释一下,这样会非常容易理解。
我们先写一个。
关于的函数有两种调用方式:以方式调用和以方式调用。我们分别以两种方式调用一下函数,看看函数内部的是什么。
上面这段代码在浏览器的执行结果如下:
从结果我们可以总结:
这里其实是JavaScript语言中this指向的知识点。
那我们可以得出这样的结论:当以方式调用某个函数时,函数内部逻辑的结果就是。
啰嗦了这么多,已经很明了了:
方法是定义在Vue原型上的一个方法:
的构造函数所在的源文件路径为,在该文件中有一行代码,该方法调用后就会将方法添加到Vue的原型对象上。这个我在前面提说过和的执行顺序,相信大家已经能理解。
那这个方法中都干了写什么呢?
大致浏览一下内部的代码实现,可以看到第一个就是为组件实例设置了一个属性。
首先分支的变量是时传递的选项。
那满足分支的逻辑就是如果存在且是一个组件。那在的时候显然不满足分支的逻辑,所以会执行分支的逻辑。
使用方法创建组件的时候会满足分支的逻辑。
在else分支中,的作用就是通过组件实例的构造函数获取当前组件的选项和父组件的选项,在通过方法将这两个选项进行合并。
这里的父组件不是指组件之间引用产生的父子关系,还是跟相关的父子关系。目前我也不太了解的相关内容,所以就不多说了。
接着就是为组件实例的赋值。
在方法内部实际上是利用中对象为将组件实例vm进行包装,然后赋值给。
关于的用法如下:
那我们简单的写一个关于的用法示例。
这个写法呢,仿照源码给设置的写法,我们给这个对象设置了。
根据函数的实现,当我们访问代理对象的某个属性时,如果属性存在,则直接返回对应的值;如果属性不存在则打印,并且返回。
当我们修改代理对象的某个属性时,如果属性存在,则为其赋新值;如果不存在则打印。
接着我们把上面这段代码放入浏览器的控制台运行,然后访问代理对象的属性:
然后在修改代理对象的属性:
结果和我们前面描述一致。然后我们在说回,它实际上也就是在访问上的某个属性时做一些验证,比如该属性是否在vm上,访问的属性名称是否合法等。
总结这块的作用,实际上就是在非生产环境中为我们的代码编写的代码做出一些错误提示。
最后就是看到有连续多个函数被调用。
我们把最后这几个函数的调用顺序和官网的对比一下:
可以发现代码和这个图示基本上是一一对应的,所以方法被称为是。下面我们将逐个解读内部按顺序调用的那些方法。
在初始化生命周期这个函数中,是当前组件的实例对象。我们看到函数内部大多数都是给这个实例对象的属性赋值。
以开头的属性称为组件的,在官网中都会有明确的解释。
属性表示的是当前组件的父组件,可以看到在循环中会一直递归寻找第一个非抽象的父级组件:。
非抽象类型的父级组件这里不是很理解,有伙伴知道的可以在评论区指导一下。
属性表示的是当前组件的。如果当前组件存在,那当前组件的会继承父组件的属性,因此直接访问就能获取到当前组件的根组件;如果当前组件实例不存在父组件,那当前组件的跟组件就是它自己。
属性表示的是当前组件实例的。在前面属性赋值的时候有这样的操作:,即将当前组件的实例对象添加到到父组件的属性中。所以数据的添加规则为:当前组件为父组件的属性赋值,那当前组件的则由其子组件来负责添加。
属性表示的是模板中注册了属性的元素或者组件实例。
在初始化事件函数中,首先给定义了一个属性,并给其赋值一个空对象。那表示的是什么呢?我们写一段代码验证一下。
我们将这段代码的逻辑简单梳理一下。
首先是组件。
接着是组件的逻辑。
因为在组件中引用了组件,因此组件和组件构成了父子关系,且组件为父组件,组件为子组件。
逻辑梳理完成后,我们运行这份代码,查看一下两个组件实例中属性的打印结果。
从打印的结果可以看到,当前组件实例的属性保存的只是父组件绑定在当前组件上的事件,而不是组件中所有的事件。
属性表示的是父组件是否通过把钩子函数绑定到当前组件上。
对于这个函数,我们首先需要关注的是这个参数。我们看一下它是怎么来的。
接着我们在浏览器中运行代码,查看结果。
从这个结果我们其实可以看到,和保存的内容实际上都是父组件绑定在当前组件上的事件。只是保存的键值稍微有一些区别:
Ok,继续我们的分析。
接着就是判断这个:假如存在的话,就执行方法。我们看一下这个方法内部实现。
可以看到在该方法内部又调用到了,先看一下这个函数的参数吧。
:这个参数我们刚说过,是父组件中添加的事件。
:这参数根据变量名翻译就是旧的事件,具体是什么目前还不太清楚。但是在初始化事件的整个过程中,调用到时传递的参数值是一个空值。所以这个值我们暂时不用关注。(在目录下全局搜索这个函数,会发现该函数在其他地方有调用,所以该参数应该是在别的地方有用到)。
: add是一个函数,函数内部逻辑代码为:
: remove也是一个函数,函数内部逻辑代码为:
:
:这个参数就不用多说了,就是当前组件的实例。
这里我们主要说一下add函数和remove函数中的两个重要代码:和。
首先是在文件中定义的一个全局变量:
在函数内部,我们能看到将组件实例赋值给了:
所以就是组件实例。当然熟悉的同学应该很快能反应上来、方法本身就是定义在组件实例上和事件相关的方法。那组件实例上有关事件的方法除了和方法之外,还有两个方法:和。
在这里呢,我们暂时不详细去解读这四个事件方法的源码实现,只截图贴出官网对这个四个实例方法的用法描述。
vm.$on
vm.$once
vm.$emit
vm.$emit的用法在 Vue父子组件通信 一文中有详细的示例。
vm.$off
函数的参数基本解释完了,接着我们在回归到函数的内部实现。
首先是这个函数,该函数就是对事件名称进行一个分解。假如事件名称,那经过该函数分解后返回的对象为:
关于函数内部的实现也非常简单,这里就直接将结论整理出来。感兴趣的同学可以去看下源码实现,源码所在位置:。
接下来就是在循环父组件事件的时候做一些的条件判断,将父组件绑定在当前组件上的事件添加到当前组件实例的属性中;或者从当前组件实例的属性中移除对应的事件。
这个逻辑就是方法内部调用实现的。详细可以去看下的源码实现,这里不再多说。而且从函数的实现,也能看出和之间的关联和差异。
函数中,基本上是在为组件实例vm上的属性赋值:、、、、。
那接下来就一一分析一下这些属性就知道在执行的过程的逻辑了。
这是来自官网对的解释,那为了方便,我还是写一个示例。
运行代码,看一下结果。
可以看到,组件的打印结果是一个包含三个键值对的对象。其中为的值保存了两个对象,这两个对象就是我们在引用组件时写的的两个元素。那为的值也是同样的道理。
为的值保存了四个,其中有一个是引用组件时写没有设置的那个元素,另外三个实际上是四个元素之间的换行,假如把内部的这样写:
那最终打印为对应的值就只包含我们没有设置的元素。
所以源代码中的函数就是解析模板中父组件传递给当前组件的元素,并且转化为赋值给当前组件实例的对象。
是中作用域插槽的内容,和查不多的原理,就不多说了。
在这里暂时给赋值了一个空对象,后续会在挂载组件调用时为其赋值。
是一个函数,该函数可以接收两个参数:
会将对象数组中的元素编译成为节点,并且放入第一个参数指定的元素中。
那前面我们讲过会将父组件传递给当前组件的节点保存起来,且对应的保存的是包含多个对象的数组,因此我们就借助来写一个示例演示一下的用法。
这个示例代码和前面介绍的代码差不多,就是在创建子组件时编写了函数,并且使用了返回模板的内容。那我们浏览器中的结果。
可以看到,正如我们所说,将中对应的 编译成为两个元素,并且放入第一个参数指定的元素中,在经过子组件的函数将的返回值进行处理,就看到了浏览器中展示的效果。
内部实现暂时不深入探究,因为牵扯到中的内容,后面了解后在学习其内部实现。
这两个属性是有关组件通信的实例属性,赋值方式也非常简单,不在多说。
函数执行的目的就是调用的生命周期钩子函数,函数的第二个参数是一个,具体指定调用哪个钩子函数。那在初始化阶段,顺序执行完 、、后就会调用钩子函数。
接下来看下源码实现。
首先根据钩子函数的名称从组件实例中获取组件的钩子函数,接着调用,函数的第三个参数为null,所以内部就是通过apply方法实现钩子函数的调用。
我们应该看到源码中是循环然后调用函数。那实际上,我们在编写组件的时候是可以,但是实际上在处理的时候只会在实例上保留最后一个重名的钩子函数,那这个循环的意义何在呢?
为了求证,我在这个钩子中打印了,然后发现这个结果是一个数组,而且只有一个元素。
这样想来就能理解这个循环的写法了。
initInjections这个函数是个Vue中的inject相关的内容。所以我们先看一下官方文档度对inject的解释。
官方文档中说和通常是一起使用的,它的作用实际上也是父子组件之间的通信,但是会建议大家在开发高阶组件时使用。
是下文中的内容。
关于和的用法会有一个特点:只要父组件使用注册了一个数据,那不管有多深的子组件嵌套,子组件中都能通过获取到父组件上注册的数据。
大致了解和的用法后,就能猜想到函数内部是如何处理的了:解析获取当前组件中的值,需要查找父组件中的中是否注册了某个值,如果有就返回,如果没有则需要继续向上查找父组件。
下面看一下函数的源码实现。
源码中第一行就调用了这个函数,并且传递了当前组件的inject配置和组件实例。那这个函数就是我们说的递归向上查找父组件的,其核心代码如下:
需要说明的是当前组件的保存的是父组件使用注册的数据,所以在循环里会先判断 是否存在,如果该值为 ,则表示父组件中包含使用注册的数据,那么就需要进一步判断父组件注册的数据是否存在当前组件中中的属性。
递归查找的过程中,对弈查找成功的数据,函数会将inject中的元素对应的值放入一个字典中作为返回值返回。
例如当前组件中的设置为:,那经过函数处理后会得到这样的返回结果:
最后在回到函数,后面的代码就是在非生产环境下,将inject中的数据变成响应式的,利用的也是双向数据绑定的那一套原理。
初始化状态这个函数中主要会初始化组件定义的一些属性:、、、、。
我们主要看一下数据的初始化,即函数的实现。
在函数里面,我们看到了一行熟悉系的代码:。这个参数就是组件中定义的数据。正如注释所说,这行代码的作用就是。
在往函数内部追踪的话,就能追到之前 [1W字长文+多图,带你了解vue2.x的双向数据绑定源码实现] 里面的的实现和调用。
所以现在我们就知道将对象变得可观测就是在实例初始化阶段的这一步中完成的。
这个函数就是我们在总结函数时提到的。那该函数也非常简单,就是为当前组件实例设置。
到这个阶段已经顺序执行完、、、、、这些方法,然后就会调用钩子函数。
内部实现在前面已经说过,这里也是一样的,所以不再重复说明。
到这里,Vue2.x的生命周期的就解读完毕了。这里我们将初始化阶段做一个简单的总结。
源码还是很强大的,学习的过程还是比较艰难枯燥的,但是会发现很多有意思的写法,还有我们经常看过的一些理论内容在源码中的真实实践,所以一定要坚持下去。期待下一篇文章。
到此这篇vue2生命周期的区别(vue生命周期详解简书)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!作者:小土豆biubiubiu
博客园:https://www.cnblogs.com/HouJiao/
掘金:https://juejin.im/user/58c61b4361ff4b005d9e894d
简书:https://www.jianshu.com/u/cb1c3884e6d5
微信公众号:土豆妈的碎碎念(扫码关注,一起吸猫,一起听故事,一起学习前端技术)
欢迎大家扫描微信二维码进入群聊讨论(若二维码失效可添加微信JEmbrace拉你进群):
码字不易,点赞鼓励哟~
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/qdvuejs/81174.html