用来解析标签的开始部分(匹配到标签开始部分时调用),主要区分标签类型、解析标签指令配置与动态绑定参数等等。
let root let currentParent function start(tag, attrs, unary, start, end) { const ns = (currentParent && currentParent.ns) || platformGetTagNamespace(tag) if (isIE && ns === 'svg') attrs = guardIESVGBug(attrs) let element: ASTElement = createASTElement(tag, attrs, currentParent) if (ns) element.ns = ns if (__DEV__) { if (options.outputSourceRange) { element.start = start element.end = end element.rawAttrsMap = element.attrsList.reduce((cumulated, attr) ={ cumulated[attr.name] = attr return cumulated }, {}) } attrs.forEach(attr =invalidAttributeRE.test(attr.name) && warn('')) } if (isForbiddenTag(element) && !isServerRendering()) { element.forbidden = true __DEV__ && warn('') } for (let i = 0; i < preTransforms.length; i++) { element = preTransforms[i](element, options) || element } if (!inVPre) { processPre(element) if (element.pre) inVPre = true } if (platformIsPreTag(element.tag)) inPre = true if (inVPre) processRawAttrs(element) else if (!element.processed) { processFor(element) processIf(element) processOnce(element) } if (!root) { root = element if (__DEV__) checkRootConstraints(root) } if (!unary) { currentParent = element stack.push(element) } else { closeElement(element) } },
start 函数在解析完标签的开始部分后被调用,接收的五个参数分别是:标签名 tag,标签的属性数组 attrs,是否自闭合 unary,起点位置 start,结束位置 end
{ type: 1, tag: tag, attrsList: attrs, attrsMap: makeAttrsMap(attrs), rawAttrsMap: {}, parent: currentParent, children: [] }
这里处理后的 input ast element,会比基础的 ast element 要多一些属性:
{ attrs: [], attrsList: [], attrsMap: { 'v-model': 'xxx' }, chidlren: [], derectives: [{ isDynamicArg: false, modifiers: undefined, name: 'model', rawName: 'model', value: 'xxx' }], events: { input: { dynamic: undefined, value: "if($event.target.composing)return;xxx=$event.target.value" } }, hasBindings: true, parent: currentParent, plain: false, props: [{ dynamic: undefined, name: 'value', value: '(xxx)' }], rawAttrsMap: {}, static: false }
虽然上面也省略了几个属性和部分属性值,但是重点属性都在里面。在 preTransforms 过程中,实际上是通过 preTransformNode() 函数处理 input 标签,并且该标签具有 v-model 配置,没有 v-model 时直接退出。
之后会判断该元素是否有动态绑定类型,如果是 动态绑定的元素类型,则会增加一个 ifConditions 配置,内部会填充 checkbox, radio 和 其他 input 类型的标签,用来根据不同的情况显示不同的展示形式(个人理解这里为什么只有三种,是因为 checkbox 和 radio 与其他的 input 输入框差别比较大,而且需要 label 标签配合)
这里会先判断 for 循环再判断 if 条件,所以才有 for 的优先级高于 if。
如果存在 v-for,会在 ast 对象中添加 for 和 forProcessed 属性,并解析条件;如果内部有文本节点要显示循环的值,则会在标签最末级创建一个文本节点并绑定显示条件
如果存在 v-if,会在 ast 对象中添加 if 和 ifProcessed 属性,并添加一个 ifConditions 属性,存放不同条件下的 ast 节点对象和渲染条件
如果有 v-once,一样会在 ast 对象中添加 once 和 onceProcessed,并且会标记 staticProcessed