generate
generate 函数⾸先实例化CodegenState然后通过 genElement(ast, state) ⽣成 code ,再把 code ⽤ with(this){return ${code}}} 包裹起来放到render中。
CodegenState
options 是传入的一些判断函数或者指令函数,CodegenState初始化实例的编译状态,因为这个函数是给实例初始化一些属性的,看到很明显就是给实例添加上了很多属性,this.xxxx 什么的。
- dataGenFns
- directives
这也是个数组,存放的是 Vue 自有指令的独属处理函数,包括以下几个指令的处理函数
v-on:绑定事件
v-bind:绑定属性
v-cloak:编译前隐藏DOM
v-model:双向绑定
v-text:插入文本
v-html:插入html
当你在模板中使用到以上的指令的时候,Vue 会调用相应的函数先进行处理
- staticRenderFns
一个数组,用来存放静态根节点的render 函数,每个实例都独有这个属性,如果没有静态根节点就为空。
genElement
可以看到基本就是递归判断当前 AST 元素节点的属性执⾏不同的代码⽣成函数。不要尝试去一下子看完全部,应该根据场景对应去阅读才是正解。
genStatic 对于静态节点的处理
1.首先genElement判断el节点是否存在staticRoot标识,并且一开始staticProcessed为false,如果满足这两个条件就调用genStatic函数。
2.genStatic首先把staticProcessed设为true,其次往staticRenderFns丢入genElement返回结果,最后render中code的返回值为_m(staticRenderFns.length - 1)。
3.再次genElement时staticProcessed为true就往下执行,执行genData中的属性的解析,然后进行genChildren,遍历children执行genNode,如果子节点类型为1说明是元素节点继续执行genElement,如果不是元素节点也不是注释节点那么就调用genText,判断是否为表达式返回对应的编码。
4.最终遍历结束后就得到了最终的编码,对于静态节点这段编码存放在staticRenderFns中。
genOnce 对v-once的处理
1.首先执行genElement外层标签不存在标识直接执行到genData然后执行genChildren,然后执行genCode,因为为元素节点所以继续执行genElement。
2.这时el存在once 标识,并且一开始onceProcessed为false,调用genOnce函数。
3.genOnce首先把onceProcessed 设为true,如果没有el.if && !el.ifProcessed和el.staticInFor条件不满足执行genStatic(el, state)。
4.genStatic首先把staticProcessed设为true,其次往staticRenderFns丢入genElement返回结果,最后render中children的返回值为_m(staticRenderFns.length - 1)。
5.再次genElement时staticProcessed为true就往下执行,执行genData解析,然后进行genChildren,遍历children执行genNode,如果子节点类型为1说明是元素节点继续执行genElement,如果不是元素节点也不是注释节点那么就调用genText,判断是否为表达式返回对应的编码。
6.最终遍历结束后就得到了最终的编码,对于静态节点这段编码存放在staticRenderFns中。
genFor
1.首先执行genElement外层标签不存在标识直接执行到genData然后执行genChildren,因为存在el.for,所以执行genElement。
2.这时el存在for标识,并且一开始forProcessed为false,调用genFor函数。
3.genFor首先获取到el.for,el.alias和el.iterator1,然后执行一些报错其中有没写Key的报错,把forProcessed设为true,然后返回了for的编码_l…然后执行genElement。
5.再次genElement时staticProcessed为true就往下执行,存在el.key执行genData对key的解析,然后进行genChildren,遍历children执行genNode,如果子节点类型为1说明是元素节点继续执行genElement,如果不是元素节点也不是注释节点那么就调用genText,判断是否为表达式返回对应的编码。
6.最终遍历结束后就得到了最终的编码。
genIf
1.首先执行genElement外层标签不存在标识直接执行到genData然后执行genChildren,因为存在el.for,所以执行genElement。
2.这时el存在if标识,并且一开始ifProcessed为false,调用genIf函数。
3.genIf首先把ifProcessed设为true,然后执行genIfConditions函数传入el.ifConditions.slice()。
4.如果没有condition直接返回'_e()',否则从conditions.shift()推出一位,如果condition存在表达式,返回三元表达式,条件?genTernaryExp -> 也就是genElement解析节点 : genIfConditions 再次执行genIfConditions
如果不存在表达式直接调用genTernaryExp去解析节点。
5.最终遍历结束后就得到了最终的编码。
class和style
1.首先执行genElement外层标签不存在标识直接执行到genData然后执行genChildren,因为也不存在标识直接执行到genData。
2.此时genData对el做dataGenFns处理,dataGenFns是平台用来处理class和style的,最终返回对象。
3.处理完data后执行genChildren,遍历children执行genNode,如果子节点类型为1说明是元素节点继续执行genElement,如果不是元素节点也不是注释节点那么就调用genText,判断是否为表达式返回对应的编码。
总结
通过对一些指令的解析,我们对从 ast -> code 这⼀步有了⼀些了解,编译后⽣成的代码就是在render时执⾏的代码。由于 genCode 的内容有很多,大概思路都是差不多,无非就是根据不同的节点属性去走不同的流程生成不同的结果,最后拼接起来的一个字符串。至于slot和事件我们后面再单独说,又是烧脑的一天。加油打工人。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!