在前面介绍组件挂载的时候,介绍过mountComponent这个函数。
主要做三件事。(监听函数的主要逻辑在之前文章讲过一次,今天主要看第一步)
1.实例化组件,并处理数据
2.创建监听函数
3.挂载组件
今天来详细看看这个函数,在开始之前,不妨问问自己几个问题,看看能否回答上来。
1.同时在data和setup中,生命一个msg变量,哪个会生效呢?
2.nextTick是如何实现在dom更新之后触发的?
3.vue中的生命周期函数是如何触发的?
实例化
实例化比较简单,就是返回一个对象。(因为现在数据还没写进去)
有个小知识点。
appContext取的是父级的appContext。
在vue2,如果全局绑定了属性,一般是通过this.$message这种形式来访问。但是在vue3中,没有了this,又想使用全局属性怎么办呢?
就可以使用getCurrentInstace获取组件实例,然后在appContext中获取。
在实例完之后,代码继续往下执行,在中间有一行不太起眼的代码,vue的数据就是在这里处理的。
我们进入这个函数,有几个需要注意的地方。
从名字也能看出来,initProps,initSlots是初始化属性跟插槽的。
那markRaw这一行是干啥的呢?直接进PublicInstanceProxyHandlers代理方法。
从这其实能看出来,组件取值会先从setup中找,其次是data。
setup处理
继续往下看,处理setup,并把setup返回值传入handleSetupResult。
判断setup结果类型,从这里可以看出来setup除了对象,是可以返回函数的,如果返回函数,则会作为渲染函数。
举个例子,在element-plus中,定义loading组件,就是通过setup返回函数来实现的。
finishComponentSetup
最后setup处理完之后,会finishComponentSetup函数。
在会finishComponentSetup函数中,还有一个重要的过程,就是制定render函数。如果没有则使用compile编译器来进行处理。
在这个函数中,主要看applyOptions(instance)函数。
生命周期来了,在这里,如果有beforeCreate,则执行钩子。
继续往后看,dataOptions就是data,如果设置了data,则通过call来改变上下文。(这就是为什么,this可以访问到数据)
数据处理好之后,就开始执行created钩子,然后注册其他生命周期。(因为其他生命周期不在这里出发,所以只是注册)
那这些函数在哪执行呢?。
在更新组件函数中,在执行组件更新之前。
nextTick
最后再来说说nextTick钩子函数。
实现非常简单。
在之前组件更新中,有一个核心的知识点是:vue在数据变化时,会触发组件更新,为了避免重复执行更新函数,使用了微任务队列,等数据都更新完了之后,再统一执行组件更新函数。
nextTick的实现就是把钩子放到微任务队列中,等组件更新函数执行完之后,再执行。
export function nextTick<T = void>(
this: T,
fn?: (this: T) => void
): Promise<void> {
const p = currentFlushPromise || resolvedPromise
return fn ? p.then(this ? fn.bind(this) : fn) : p
}
总结
总结一下今天的知识点。
1.appContext在上下文的时候,指定为父级appContext。(也就是全局上下文)
2.vue的变量访问顺序,做了统一的代理,先setup,其次是data。
3.setup可以返回函数作为渲染函数。
4.组件实例如果没有render函数,会使用compile编译
5.vue2写法,this之所以能访问到,是因为做了this重定向
6.生命周期在处理组件数据的各个阶段调用
7.nextTick之所以能在组件更新执行完成之后执行,是因为用了微任务。
如果看完有收获,欢迎点赞、评论、分享支持。你的支持和肯定,是我写作的动力