This is the 24th day of my participation in the First Challenge 2022.

Previously on & Background

ProcessKey, processRef, checkInFor, processSlotContent:

  1. ProcessKey: Checks the key attribute on the element and the restrictions on using the key;

  2. ProcessRef: Handles the ref property, if ref is wrapped by V-for, ref points to an array;

  3. CheckInFor: Checks if the parent element of the current element has a V-for directive;

  4. ProcessSlotContent: processSlotContent, get slot name, dynamic slot, and v-slot instructions after 2.6.x;

Second, the processSlotOutlet

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

Method parameters: EL, AST node object

The slot () method parses the slot tags of the closed and gets the name of the named slot and sets it to the EL property.

function processSlotOutlet (el) {
  if (el.tag === 'slot') {
    el.slotName = getBindingAttr(el, 'name')

    // Do not use keys on slot tags
    if(process.env.NODE_ENV ! = ='production' && el.key) {
      warn(
        ` `key` does not work on <slot> because slots are abstract outlets ` +
        `and can possibly expand into multiple elements. ` +
        `Use the key on a wrapping element instead.`,
        getRawBindingAttr(el, 'key')}}}Copy the code

Third, processComponent

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

Method parameters: EL, AST node object

The El.inlineTemplate = true () method parses dynamic components and sets the el.component.ponent = is property binding. If the Component tag contains an inline-template property, set el.inlineTemplate = true

Take the following code for example:

<component :is="compName" inline-template>
  <div>some content,not slot other than compName's template</div>
</component>
Copy the code
Function processComponent (el) {let binding; el.component = compName if ((binding = getBindingAttr(el, 'is'))) {el.component.ponent = binding} If (getAndRemoveAttr(el, 'inline-template')! If (getAndRemoveAttr(el, 'inline-template')! = null) { el.inlineTemplate = true } }Copy the code

Four, transforms

Transforms Is not a method, but an array of methods, derived via pluckModuleFunction(options.modules, ‘transformNode’), Just like the preTransformNode, postTransform methods;

Modules come from createCompiler(baseOpitons). Modules in baseOptions have klass,style, and Model items. PluckModuleFunctions pick out the specified methods from these three to compose an array;

The transformNode methods only klass and style are exported, but model is not exported. So there are two methods in the Transforms array that handle the AST’s class name and style style, respectively;

Vue bind:class, Vue bind:class, Vue bind:class, Vue bind:class, Vue bind:class Add el. StaticClass, el. ClassBinding, El. StaticStyle and el. StyleBinding.

4.1 transformNode < – modules/style.css. Js

Methods location: SRC/platforms/web/compiler/modules/style.css. Js – > functions provides transformNode

Method parameters:

  1. el.astThe node object
  2. Options: createCompiler (baseOptions)Method receives

Unbind the v-bin:style / :style attributes from el and assign them to el. StaticStyle and el. StyleBinding ‘respectively

function transformNode (el: ASTElement, options: CompilerOptions) {
  const warn = options.warn || baseWarn

  // Get 
      
coloer: red
const staticStyle = getAndRemoveAttr(el, 'style') if (staticStyle) { if(process.env.NODE_ENV ! = ='production') { const res = parseText(staticStyle, options.delimiters) // if you parse to delimiter from xx, it is a dynamic style // If
, use :style="val"
if (res) { warn( `style="${staticStyle}": ` + 'Interpolation inside attributes has been removed. ' + 'Use v-bind or the colon shorthand instead. For example, ' + 'instead of <div style="{{ val }}">, use <div :style="val">.', el.rawAttrsMap['style'])}}// assign a staticStyle to el. StaticStyle el.staticStyle = JSON.stringify(parseStyleText(staticStyle)) }
// Assign to el.styleBinding const styleBinding = getBindingAttr(el, 'style'.false /* getStatic */) if (styleBinding) { el.styleBinding = styleBinding } } Copy the code

4.2 tranfromNode < – modules/class. Js

function transformNode (el: ASTElement, options: CompilerOptions) {
  / / log
  const warn = options.warn || baseWarn

  // <div class="someStaticClassName"></div>
  // Get the class attribute value on the element someStaticClassName
  const staticClass = getAndRemoveAttr(el, 'class')

  if(process.env.NODE_ENV ! = ='production' && staticClass) {
    const res = parseText(staticClass, options.delimiters)
    
      
//
if (res) { warn( `class="${staticClass}": ` + 'Interpolation inside attributes has been removed. ' + 'Use v-bind or the colon shorthand instead. For example, ' + 'instead of <div class="{{ val }}">, use <div :class="val">.', el.rawAttrsMap['class'])}}// assign the staticClass attribute to el.staticClass if (staticClass) { el.staticClass = JSON.stringify(staticClass.replace(/\s+/g.' ').trim()) } // Get the dynamically bound class property value and copy it to el.classBinding const classBinding = getBindingAttr(el, 'class'.false /* getStatic */) if (classBinding) { el.classBinding = classBinding } } Copy the code

Fifth, processAttrs

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

Method parameters: EL, AST node object

The attrsList () method iterates over the attributes on the object attrsList to obtain the name and value of each item.

  1. Determine if the attribute is a directive if it is:
    • 1.1 set upel.hasBinding = true;
    • 1.2 Save modifiers on parse instructions tomodifiersVariable, and then replace the modifier part on the property with an empty string;
    • 1.3 Checking attributes with renameWhether to useV - bind or:Dynamically bound values to attributesnameDynamic binding ofV - bind or:Replace with empty, leaving only the bound property itself; Then parsingvalueFilter on;
    • 1.4 Then use the re to match whether there are dynamic parameters on the instruction, and the result assigns a valueisDynamic, the so-called dynamic parameter, for example<a v-bind:[attributeName]="url"> ... </a>In square bracketsattrbuteNameIs the dynamic parameter, when the dynamic parameter is obtained, the parameter name in square brackets is obtained, i.ename.slice(1, -1)
    • 1.5 If modifiermodifiersNot null, if there are no dynamic parametersProp, camelThe modifier; To deal withsyncThe modifier,syncThe modifier is aUpdate: the property nameSyntactic sugar for the event name that is executed when the event is triggeredsyncGenCode, which is responsible for updating dataAssignment or $set)
    • 1.6 if it isv-onInstruction that handles dynamic parameter names and gets withoutv-onor@Gets the part without square brackets if it is a dynamically bound parameter, for example<div v-on:[someDynamicEventName]></div> someDynamicEventNameAnd then calladdHandlerRebind events;
    • 1.7 The last is the common instruction, which obtains the common instruction name and parameters, determines whether there are dynamic parameters, and then invokesaddDirective Add instruction:el.directives.push()
  2. If it is not an instruction specification or a normal literal property, then calladdAttr()namevalueSet it toel.dynamicAttrsorel.attrsHere you can see it very clearlyattrsIs a static property, willel.plainSet tofalse; If not component andname'muted'And must usepropCalled when a property is boundaddPropThe bindingmutedProperties;
function processAttrs (el) {
  const list = el.attrsList
  let i, l, name, rawName, value, modifiers, syncGen, isDynamic
  for (i = 0, l = list.length; i < l; i++) {
    name = rawName = list[i].name
    value = list[i].value
    if (dirRE.test(name)) {
      // If it is a command
      // mark element as dynamic
      el.hasBindings = true
      / / modifier
      modifiers = parseModifiers(name.replace(dirRE, ' '))
      // Syntax modifiers that support the.foo abbreviation
      if (process.env.VBIND_PROP_SHORTHAND && propBindRE.test(name)) {
        (modifiers || (modifiers = {})).prop = true
        name = `. ` + name.slice(1).replace(modifierRE, ' ')}else if (modifiers) {
        // The name does not contain modifiers
        name = name.replace(modifierRE, ' ')}if (bindRE.test(name)) { // v-bind
        name = name.replace(bindRE, ' ')
        value = parseFilters(value)
        isDynamic = dynamicArgRE.test(name) // Whether it is a dynamic parameter
        if (isDynamic) {
          name = name.slice(1, -1)}if( process.env.NODE_ENV ! = ='production' &&
          value.trim().length === 0
        ) {
          warn(
            `The value for a v-bind expression cannot be empty. Found in "v-bind:${name}"`)}if (modifiers) {
          if(modifiers.prop && ! isDynamic) { name = camelize(name)if (name === 'innerHtml') name = 'innerHTML'
          }
          if(modifiers.camel && ! isDynamic) { name = camelize(name) }if (modifiers.sync) {
            // Handle the sync modifier, which is how the sync modifier works
            syncGen = genAssignmentCode(value, `$event`)
            if(! isDynamic) { addHandler( el,`update:${camelize(name)}`,
                syncGen,
                null.false,
                warn,
                list[i]
              )
              if(hyphenate(name) ! == camelize(name)) { addHandler( el,`update:${hyphenate(name)}`,
                  syncGen,
                  null.false,
                  warn,
                  list[i]
                )
              }
            } else {
              // handler w/ dynamic event name
              addHandler(
                el,
                `"update:"+(${name}) `,
                syncGen,
                null.false,
                warn,
                list[i],
                true // dynamic)}}}if((modifiers && modifiers.prop) || ( ! el.component && platformMustUseProp(el.tag, el.attrsMap.type, name) )) { addProp(el, name, value, list[i], isDynamic) }else {
          addAttr(el, name, value, list[i], isDynamic)
        }
      } else if (onRE.test(name)) { // v-on
        name = name.replace(onRE, ' ')
        isDynamic = dynamicArgRE.test(name)
        if (isDynamic) {
          name = name.slice(1, -1)
        }
        addHandler(el, name, value, modifiers, false, warn, list[i], isDynamic)
      } else { // normal directives
        name = name.replace(dirRE, ' ')
        // parse arg
        const argMatch = name.match(argRE)
        let arg = argMatch && argMatch[1]
        isDynamic = false
        if (arg) {
          name = name.slice(0, -(arg.length + 1))
          if (dynamicArgRE.test(arg)) {
            arg = arg.slice(1, -1)
            isDynamic = true
          }
        }
        addDirective(el, name, rawName, value, arg, isDynamic, modifiers, list[i])
        if(process.env.NODE_ENV ! = ='production' && name === 'model') {
          checkForAliasModel(el, value)
        }
      }
    } else {
      // literal attribute
      if(process.env.NODE_ENV ! = ='production') {
        const res = parseText(value, delimiters)
        if (res) {
          warn(
            `${name}="${value}": ` +
            'Interpolation inside attributes has been removed. ' +
            'Use v-bind or the colon shorthand instead. For example, ' +
            'instead of <div id="{{ val }}">, use <div :id="val">.',
            list[i]
          )
        }
      }
      addAttr(el, name, JSON.stringify(value), list[i])
      // #6887 firefox doesn't update muted state if set via attribute
      // even immediately after element creation
      if(! el.component && name ==='muted' &&
          platformMustUseProp(el.tag, el.attrsMap.type, name)) {
        addProp(el, name, 'true', list[i])
      }
    }
  }
}
Copy the code

Six, summarized

This essay continues the discussion of closeElement’s tool methods, as follows:

  1. ProcessSlotOutlet: Resolves the slot labels of the closed and gets the slot name set to the EL;

  2. ProcessComponent: Resolves dynamic components, resolves IS properties and inline-template

  3. Transforms: transoformNode methods exported by the class/style module process static and dynamic class names or styles

  4. ProcessAttrs: Handles attrs on elements, parameters of instructions, event bindings, modifiers, and so on;

This is the end of closeElment, and all the logic of options.start has been completed