网站优化

网站优化

Products

当前位置:首页 > 网站优化 >

Vue源码解析:编译之generate方法

GG网络技术分享 2025-03-18 16:08 0


先简单复习一下Vue的编译过程,整个过程分为三个步骤:

第一步是parse解析阶段,前面的章节已经讲过parse方法的具体实现,该方法主要是将template编译成易于处理的抽象语法树(ast)。

第二步是optimize优化阶段,该阶段主要是将template中的静态节点在ast中标记出来,方便后续生成虚拟Dom的时候进行复用。

第三步是generate生成代码阶段,也是我们这章要学习的部分。该阶段是将ast树转换成能生成对应虚拟Domrender函数。

这一章我们主要讨论generate阶段,看看抽象语法树是如何转换成render函数的。

with语法

我们先看下最终生成的代码代表的是什么意思:

with(this){return_c("div",[_v("编译")])}

从生成的代码可以看出,render函数是以with开头的,我们先了解下with是如何使用的。

constobj={a:3}with(obj){console.log(a)// 3console.log(this.a)// undefinedconsole.log(b)// 报错}

借用mdn上的一句话:with语句扩展一个语句的作用域链。本来访问a的时候是访问的全局作用域,加了with之后,访问a的作用域则是objwith使用起来相对比较简单。回到Vuerender函数中,可以知道render函数里的作用域就是Vue的实例vm,所以render执行的时候,访问变量实质上就是访问Vue实例上的属性。至于为什么要使用with语法,可以看下尤大大的一篇回答

renderHelpers

还是那段编译生成的代码,在with内部的代码中有_c_v这样的方法。由于this是指向Vue实例的,所以访问_c的时候其实访问的是vm._c。但是_c_v这些方法是哪里定义的呢?

with(this){return_c("div",[_v("编译")])}

这就要追溯到Vue构造函数与原型的章节了,在src/core/instance/render.js文件中找到renderMixin方法,这个方法是在我们学习Vue原型设计的时候提到的:

exportfunctionrenderMixin(Vue:Class<Component>){// install runtime convenience helpersinstallRenderHelpers(Vue.prototype)Vue.prototype.$nextTick=function(fn:Function){...}Vue.prototype._render=function():VNode{...}}

./render-helpers找到installRenderHelpers函数:

exportfunctioninstallRenderHelpers(target:any){target._o=markOncetarget._n=toNumbertarget._s=toStringtarget._l=renderListtarget._t=renderSlottarget._q=looseEqualtarget._i=looseIndexOftarget._m=renderStatictarget._f=resolveFiltertarget._k=checkKeyCodestarget._b=bindObjectPropstarget._v=createTextVNodetarget._e=createEmptyVNodetarget._u=resolveScopedSlotstarget._g=bindObjectListenerstarget._d=bindDynamicKeystarget._p=prependModifier}

installRenderHelpers主要任务就是挂载了渲染需要用到的函数!所以调用_v就是调用createTextVNode方法,从字面意思我们就可以知道,其实它就是创建一个文本的Vnode节点。但是这里并没有定义_c,那么_c在哪呢?还记得数据初始化环节吗,同样是在src/core/instance/render.js文件中,不过是initRender方法:

exportfunctioninitRender(vm:Component){...vm._c=(a,b,c,d)=>createElement(vm,a,b,c,d,false)vm.$createElement=(a,b,c,d)=>createElement(vm,a,b,c,d,true)...}

_c同样是创建Vnode节点的函数。所以render函数就是由一堆生成Vnode节点函数的集合。接下来我们看下具体是如何使用这些函数的。

generate

generate过程的代码都是在src/compiler/codegen目录中,里面只有两个文件,相对来说比较少。在index.js中找到generate函数:

exportfunctiongenerate(ast:ASTElement|void,options:CompilerOptions):CodegenResult{conststate=newCodegenState(options)constcode=ast?(ast.tag==="script"?"null":genElement(ast,state)):"_c("div")"return{render:`with(this){return${code}}`,staticRenderFns:state.staticRenderFns}}

里面的核心实现是调用了genElement方法:

if(el.staticRoot

标签:

提交需求或反馈

Demand feedback