“This is the 21st day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

Previously on & Background

This article continues with the previous discussion of the options.start utility methods:

  1. ProcessPre: Checks whether there is a v-pre directive on the element, if there is, set el. Pre to true;

  2. GetAndRemoveAttr: Get the value of the specified attribute name from el.attrsMap and remove the attribute from the el.attrsList array. If removeFromMap is passed, remove the attribute from attrsMap.

  3. PlatformIsPreTag: Checks whether it is a pre tag.

  4. ProcessRawAttr: Copies the attributes on the element into the el.attrs array, which has static attributes and ignores them when the data changes;

  5. ProcessFor: processes the V-for instruction, resulting in {for: iterable, alias: iterable entry name};

This article goes on to discuss the utility methods of options.start: processIf, processOnce, checkRootConstraints, closeElement ‘and some of their internal methods

Second, the processIf

Methods location: SRC/compiler/parser/index. The js – > fucntion processIf

Method parameters: EL, AST node object

El.if, el.elseIf, el.else; el.else; el.elseIf; el.else; el.else; el.elseIf; el.else;

AddIfCondition (el, {exp, block}) is called when parsing to V-if to add an item to el.ifconditions; Exp is the V-if expression and block is the AST node el, which identifies the AST node represented by the block when the condition represented by exp is true

function processIf (el) {
  const exp = getAndRemoveAttr(el, 'v-if')
  if (exp) {
    el.if = exp
    addIfCondition(el, {
      exp: exp,
      block: el
    })
  } else {
    // the el.else value is true
    if (getAndRemoveAttr(el, 'v-else') != null) {
      el.else = true
    }
    const elseif = getAndRemoveAttr(el, 'v-else-if')
    if (elseif) {
      el.elseif = elseif
    }
  }
}
Copy the code

2.1 addIfCondition

Methods location: SRC/compiler/parser/index. The js – > function addIfCondition

Method parameters:

  1. el.ASTThe node object
  2. condition:{ exp, block }.expv-ifThe value of the expression, the condition,blockexp

Represents the AST element rendered when the condition is set

If el.ifConditions does not exist, create an empty array of ifConditions.

export function addIfCondition (el: ASTElement, condition: ASTIfCondition) {
  if(! el.ifConditions) { el.ifConditions = [] } el.ifConditions.push(condition) }Copy the code

Third, processOnce

Methods location: SRC/compiler/parser/index. The js – > function processOnce

Method argument: Element, AST node object

The element.once = true () method handles the v-once directive if the AST node has a v-once directive for element.once = true;

function processOnce (el) {
  const once = getAndRemoveAttr(el, 'v-once')
  if(once ! =null) {
    el.once = true}}Copy the code

Four, checkRootConstraints

Methods location: SRC/compiler/parser/index. The js – > function checkRootConstraints

Method parameters: EL, AST node object

Methods: Check the restrictions on the root node. There are some capabilities that can be restricted when used as the root node on the template. For example,
or
tags cannot be used as root elements, and v-for directives cannot be used on root nodes

function checkRootConstraints (el) { if (el.tag === 'slot' || el.tag === 'template') { warnOnce( `Cannot use <${el.tag}>  as component root element because it may ` + 'contain multiple nodes.', { start: el.start } ) } if (el.attrsMap.hasOwnProperty('v-for')) { warnOnce( 'Cannot use v-for on stateful component root element  because ' + 'it renders multiple elements.', el.rawAttrsMap['v-for'] ) } }Copy the code

Fifth, closeElement

Methods location: SRC/compiler/parser/index. The js – > functions provides closeElement

Method argument: Element, AST node object

The closeElement in options.start () method handles the closing logic directly when processing options.start ().

CloseElement does a few things:

  1. calltrimEndingWhitespaceRemoves whitespace from its own node
  2. ifelement.processedDon’t fortrueThe callprocessElementHandle properties on nodes;
  3. ifstackNot null and current parameterelmentnotrootWhen, want to lookstackNot for empty reasons if yesrootFor use onv-if,v-else-ifCondition statement, which is allowed; But if thestackNot empty and not in usev-ifThis means that there are multiple root elements. This is inVueIs not allowed, give a hint;
  4. Organization node relationship,
    • 4.1 ifelementThere arev-else-iforv-else, the callprocessIfConditionsDeal with the currentelementcurrentParentThe relationship between;
    • 4.2 Otherwise, determine whether there is anyelement.slotScopeIf socurrentParent.scopedSlotsAdd a new entry,keyelement.slotTargetor"default".
    • 4.3 The value is currentelement; Finally, the current elementpushcurrentParent.childrenIn, and then willelement.parentSet tocurrentParent; Of course,closeElementWhen processing a non-self-closing tag, all non-slot child elements of the element are added tocurrentParent.children;
  5. To deal withelement.childrenSo that the last value does not contain the scope slot, and then againtrimEndingWhitespace;
  6. maintenanceInVPre, inPre
  7. callpostTransformsMethod in, rightelementPost-processing;postTransforms pluckModuleFunction(options.modules, 'postTransformNode')In thewebPlatform,modulesIn theklass/style/modelNone of them are exportedpostTransformNodeMethod, sopostTransformsIs an empty array
function closeElement (element) {
  trimEndingWhitespace(element)
  if(! inVPre && ! element.processed) { element = processElement(element, options) }// tree management
  if(! stack.length && element ! == root) {// If the stack is not empty and v-if/ V-else /v-else is used on root, this is allowed
    if (root.if && (element.elseif || element.else)) {
   
      addIfCondition(root, {
        exp: element.elseif,
        block: element
      })
    } else if(process.env.NODE_ENV ! = ='production') {
      // If there are multiple root nodes, this is not allowed}}if(currentParent && ! element.forbidden) {if (element.elseif || element.else) {
      processIfConditions(element, currentParent)
    } else {
      if (element.slotScope) {
        // scoped slot
        // keep it in the children list so that v-else(-if) conditions can
        // find it as the prev node.
        const name = element.slotTarget || '"default"'; (currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element } currentParent.children.push(element) element.parent = currentParent } }// element.children does not contain scope slots
  element.children = element.children.filter(c= >! (c: any).slotScope)// Remove the children whitespace again
  trimEndingWhitespace(element)

  // Maintain inVPre, inPre,
  // If element.pre indicates that the current element uses v-pre
  // Now closeElement, you need to set inVPre and inPre to false before you start processing the start tag again
  if (element.pre) {
    inVPre = false
  }
  if (platformIsPreTag(element.tag)) {
    inPre = false
  }
  // Call the postTransforms processing method
  for (let i = 0; i < postTransforms.length; i++) {
    postTransforms[i](element, options)
  }
}
Copy the code

5.1 trimEndingWhitespace

Methods location: SRC/compiler/parser/index. Js – > trimEndingWhitespace

Method parameters: EL, AST node object

The pre () method removes blank elements from all children of the current node if they are not in the pre tag

function trimEndingWhitespace (el) { if (! inPre) { let lastNode while ( (lastNode = el.children[el.children.length - 1]) && lastNode.type === 3 && lastNode.text === ' ' ) { el.children.pop() } } }Copy the code

5.2 processElement

Methods location: SRC/compiler/parser/index. The js – > function processElement

Method parameters:

  1. element: astNode object;
  2. options:createCompilerThe receivedbaseOptions

The class, style, v-bind, V-ON and other instructions are added to the element. Finally, element is returned.

export function processElement (element: ASTElement, options: CompilerOptions) {
  // Handle keys on elements: set el.key = valprocessKey(element) element.plain = ( ! element.key && ! element.scopedSlots && ! element.attrsList.length )// Handle the ref attribute
  processRef(element)

  // Process the slot contents
  processSlotContent(element)

  
  processSlotOutlet(element)

  processComponent(element)

 
  for (let i = 0; i < transforms.length; i++) {
    element = transforms[i](element, options) || element
  }

 
  processAttrs(element)
  return element
}
Copy the code

5.3 processIfConditions

Methods location: SRC/compiler/parser/index. The js – > function processIfConditions

Method parameters:

  1. el.astNode object;
  2. parent.elThe parent elementastNode object;

AddIfConditions () addIfConditions add elseIf or else block if the prev has an if attribute

function processIfConditions (el, parent) {
  const prev = findPrevElement(parent.children)
  if (prev && prev.if) {
    addIfCondition(prev, {
      exp: el.elseif,
      block: el
    })
  } else if(process.env.NODE_ENV ! = ='production') {
    warn(
      `v-${el.elseif ? ('else-if="' + el.elseif + '"') : 'else'} ` +
      `used on element <${el.tag}> without corresponding v-if.`,
      el.rawAttrsMap[el.elseif ? 'v-else-if' : 'v-else'])}}Copy the code

Six, summarized

The options.start method is an internal method of the options.start method.

  1. ProcessIf: Processes v-if/ V-else -if/ V-else on ast node objects, adding these conditional rendering information to el.if/el.elseif/el.else;

  2. ProcessOnce: process v-once, get el.once = true;

  3. CheckRootContraints: Checks for restrictions on root elements, such as slot and template.

  4. Options. start executes the closeElement and its utility methods when it receives an autistic tag. The closeElement method is not covered here, but will be covered in the next two articles