在学习vue源码(六)熟悉模板编译原理之前我们讲过模板编译分为解析器、优化器、代码生成器。在学习vue源码(七)手写解析器中,我们已经学习了解析器的实现方式,现在我们来看看优化器是如何实现的。优化器的目标是找出那些静态节点并标记它们。优化器的实现原理主要分为两步:第一步:递归给所有节点添加静态属性,判断是否为静态节点第二步:标记所有静态节点根节点和静态节点指的是DOM不需要改变的节点,例如:
我是静态节点,我不需要改变
在AST中实现,静态节点是指静态属性为true的节点,比如as{type:1,tag:'p',staticRoot:false,static:true,....}标记静态节点有两个好处:不需要每次重新渲染时都为静态节点创建新节点的过程可以跳过VirtualDOM中的补丁。什么是静态根节点?答:子节点都是静态节点的节点就是静态根节点,例如:
- 我是静态节点,不用改
- 我是静态节点2、我不需要改变改变
- 我是静态节点3、我不需要改变
ul是静态根节点。在AST中实现,静态根节点是指staticRoot属性为true的节点,比如上面提到的{type:1,tag:'ul',staticRoot:false,static:true,.....}:optimizer的实现原理主要分为两步:第一步:递归地为所有节点添加静态属性,判断是否为静态节点第二步:标记所有静态根节点。源码是这样实现的:functionoptimize(root,options){if(!root)return//第一遍:标记所有非静态节点//第二遍:markstaticroots.markStaticRoots(root);}现在我们来看第一步:如何给所有的节点都标记static属性?vue判断一个节点是否为静态节点并不难:先根据是否为静态节点做一个标记node.static=isStatic(node),然后循环children。如果子节点中有一个节点不是静态节点,则将当前节点的标志更改为false:node.static=false。如代码所示:functionmarkStatic(node){node.static=isStatic(node);如果(node.type===1){for(vari=0,l=node.children.length;i
不能是像上面这样的自定义组件,元素节点的父节点不能是带有v-for的模板,元素节点上不能出现额外的属性。附加属性是指不能出现的`typetagattrsListattrsMapplainparentchildrenattrsstaticClassstaticStyle`以外的属性。如果出现其他属性,则认为当前节点不是静态节点。只有满足上述所有条件的节点才会被视为静态节点。但是有一个问题:递归是从上到下标记的。如果父节点标记为静态节点,而在递归到后面的过程中子节点标记为动态节点,那么就会出现矛盾,所以需要在子节点标记之后,标记父节点再次节点,如代码所示如果(node.type===1){for(vari=0,l=node.children.length;i