“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:
-
ProcessPre: Checks whether there is a v-pre directive on the element, if there is, set el. Pre to true;
-
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.
-
PlatformIsPreTag: Checks whether it is a pre tag.
-
ProcessRawAttr: Copies the attributes on the element into the el.attrs array, which has static attributes and ignores them when the data changes;
-
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:
el
.AST
The node objectcondition
:{ exp, block }
.exp
是v-if
The value of the expression, the condition,block
是exp
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,
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:
- call
trimEndingWhitespace
Removes whitespace from its own node - if
element.processed
Don’t fortrue
The callprocessElement
Handle properties on nodes; - if
stack
Not null and current parameterelment
notroot
When, want to lookstack
Not for empty reasons if yesroot
For use onv-if
,v-else-if
Condition statement, which is allowed; But if thestack
Not empty and not in usev-if
This means that there are multiple root elements. This is inVue
Is not allowed, give a hint; - Organization node relationship,
- 4.1 if
element
There arev-else-if
orv-else
, the callprocessIfConditions
Deal with the currentelement
和currentParent
The relationship between; - 4.2 Otherwise, determine whether there is any
element.slotScope
If socurrentParent.scopedSlots
Add a new entry,key
是element.slotTarget
or"default"
. - 4.3 The value is current
element
; Finally, the current elementpush
到currentParent.children
In, and then willelement.parent
Set tocurrentParent
; Of course,closeElement
When processing a non-self-closing tag, all non-slot child elements of the element are added tocurrentParent.children
;
- 4.1 if
- To deal with
element.children
So that the last value does not contain the scope slot, and then againtrimEndingWhitespace
; - maintenance
InVPre, inPre
- call
postTransforms
Method in, rightelement
Post-processing;postTransforms
是pluckModuleFunction(options.modules, 'postTransformNode')
In theweb
Platform,modules
In theklass/style/model
None of them are exportedpostTransformNode
Method, sopostTransforms
Is 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:
element
:ast
Node object;options
:createCompiler
The 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:
el
.ast
Node object;parent
.el
The parent elementast
Node 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.
-
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;
-
ProcessOnce: process v-once, get el.once = true;
-
CheckRootContraints: Checks for restrictions on root elements, such as slot and template.
-
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