好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Vue3初始化如何调用函数

Vue3初始化调用函数

createApp({}).mount(‘#app')

入口文件 runtime-dom/src/index.tx

createApp -> createRenderer -> createBaseRenderer(这里还创建了render函数以及一系列渲染时的函数) -> createAppAPI(返回了真正的createApp方法),返回了 实例 app, 然后 app.mount([#app]) -> createVNode -> render(vnode,rootcontainier,isSVG) -> patch -> processComponent -> mountComponent(初次渲染)或者是updateComponent ->(createComponentInstance , setupComponent,setupRenderEffect) 对于setupComponent,有setup函数和没有setup函数分情况处理,如果有就走setup函数处理,初始化props等需要传递给setup函数的参数,调用setup,setupComponent->finishComponentSetup(在这里会处理 2.x版本的options选项初始化), 对于setupRenderEffect,执行一系列生命钩子函数,创建渲染ReactiveEffect,并执行了**effect.run()**方法

ReactiveEffect

类似于 vue2.x 的Watcher, computed,watch,渲染过程中componentUpdateFn也使用了 ReactiveEffect,

const effect = new ReactiveEffect(fn,…)后,除了计算属性会在被访问时才去调用effect.run()->调用fn(),在fn里访问响应式变量,收集依赖,其余的setupRenderEffect,watch,watchEffect,均会在创建ReactiveEffect后调用effect.run()收集依赖,其中

setupRenderEffect 会访问依赖的响应变量 watch(source,cb,options) ,会执行访问source的函数,收集依赖 watchEffect(fn) ,会自动执行一次fn收集依赖 effect(fn,options) ,其中options有个lazy:true选项,表示不立即执行fn函数收集依赖,返回一个run函数,再次调用run(),执行一次fn函数,收集依赖

// 1.计算属性
// computed.ts
// ComputedRefImpl类构造函数调用了new ReactiveEffect
this.effect = new ReactiveEffect(getter, () => {
      if (!this._dirty) {
        this._dirty = true
        triggerRefValue(this)
      }
    })
    
// 2. effect
// effect.ts
// effect函数中,可以接收第二个参数effect(fn,{lazy:true}),表示不立即执行
  const _effect = new ReactiveEffect(fn)
// 3. apiWatch.ts doWatch方法
// watch和watchEffect都是通过doWatch函数来,在这里调用new ReactiveEffect,然后根据不同情况执行effect.run(),对于watchEffect就是//执行器回调,对于watch就是访问监听的数据,然后收集依赖
  const effect = new ReactiveEffect(getter, scheduler)
// 4. render.ts
//在 setupRenderEffect中
const effect = (instance.effect = new ReactiveEffect(
      componentUpdateFn,//更新组件函数
      () => queueJob(update),
      instance.scope // track it in component's effect scope
    ))

Vue3程序初始化流程

初始化

在vue3中,程序的初始化不再沿用vue2的new Vue()方法,而是使用了createApp。在createApp中发生了什么呢?

改写的原因

createApp是一个Vue中的工厂函数,以函数的方式进行导入和调用。而函数式的好处是

1、消灭了原来挂载在Vue上的静态方法,变成实例方法,可以减少内存占用,便于tree-shaking,减小了打包体积;

2、因为函数式和class装饰器对ts的支持好,使用函数的方式调用,可以更好的支持ts,提高类型支持

3、根组件的api,如data要和子组件的api保持相同的格式,挂载从$mount改为mount,简化了api并统一了api的一致性

4、new Vue中挂载的方法会造成全局污染,不能独立出来,createApp可以相互独立,并按需挂载。

流程实现

mount

const Vue = {
	createApp(options) {
		//返回app实例
		return {
			mount(selector){
				// 获取渲染函数,编译结果
				// 渲染dom,追加到宿主元素
			}
			compile(template){
			//返回render
				return function render(){
					//描述视图
				}
			}
		}
	}
}

在调用createApp时,如果options中无render,则初始化组件,调用compile产生一个render,若有render则直接挂载;

Vue2中追加元素使用比较替换的方式,diff元素间区别进行对比判断,Vue3中则是直接进行删除重加。

可以在setup或者是data中定义响应式变量, setup的优先级更高。

createApp

Vue暴露的两个初始化的函数,createApp和createRenderer,他们之间的调用关系 

/*暴露给Vue的createApp*/
function createApp(options){
?? ?const renderer = ?Vue.createRenderer({
?? ??? ?/*定义一些平台特有的api,一些实例*/
?? ??? ?aaa(){},
?? ??? ?bbb(){}
?? ?})
?? ?/*用户调用的createApp,实际上是渲染器的createApp*/
?? ?return renderer.createApp()
}
function createRenderer({aaa,bbb}){
?? ?/*获得渲染器*/
?? ?/*这个createApp是函数内部的*/
?? ?return createApp(options){
?? ??? ?/*挂载逻辑*/
?? ??? ?return {
?? ??? ??? ?/*返回App实例*/
?? ??? ?}
?? ?}
}

源码流程

1、用户调用createApp方法 =》 通过ensureRenderer得到渲染器

2、渲染器调用createRender =》※调用工厂函数baseGreateRenderer,这个函数中定义了patch和diff等,最终会return一个render用来给spa页面进行渲染,一个hydrate用来给ssr页面进行注水,还有一个函数的createApp(不同于Vue的createApp)

3、在函数的createApp中会定义程序的实例方法,如mount,get,set,use,mixin等

4、mount实例方法会去查看是否有根组件挂载,使用什么方法进行挂载(spa/ssr)

5、render方法调用patch方法进行打补丁

6、patch方法根据传入的节点类型进行挂载方法的判断,如果首次挂载则为挂载component,之后是挂载element(patch方法会将vnode转化为node节点)

7、patch方法执行内部processComponent方法,最终执行mountComponent方法,也就是Vue2中$mount最终执行的方法

初始化流程

1、根组件的实例化:调用createComponentInstance

2、初始化根组件:调用setupComponent方法,也就是Vue2中的this.$_init方法,用来将选项进行合并,并设置钩子和响应式

3、安装render函数的副作用函数:setupRendererEffect

在Vue3中取消了watcher改为了副作用函数,副作用函数会在每次响应式数据发生变化的时候重新执行,内部的render函数的执行会触发依赖收集,这样当响应式数据变化时,响应式组件就会更新。

PS:与react中的useEffect不同的方面是,useEffect需要手动的收集依赖,而Vue中的effect()会自动的收集依赖。 

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

查看更多关于Vue3初始化如何调用函数的详细内容...

  阅读:84次