Просмотр исходного кода

refactor(parser): move element self processing to after children

This allows element processing logic to be based on its sub tree
content, e.g. $slot usage detection
Evan You 7 лет назад
Родитель
Сommit
583dd01158
1 измененных файлов с 66 добавлено и 53 удалено
  1. 66 53
      src/compiler/parser/index.js

+ 66 - 53
src/compiler/parser/index.js

@@ -97,6 +97,40 @@ export function parse (
   }
   }
 
 
   function closeElement (element) {
   function closeElement (element) {
+    if (!inVPre && !element.processed) {
+      element = processElement(element, options, currentParent)
+    }
+    // tree management
+    if (!stack.length && element !== root) {
+      // allow root elements with v-if, v-else-if and v-else
+      if (root.if && (element.elseif || element.else)) {
+        if (process.env.NODE_ENV !== 'production') {
+          checkRootConstraints(element)
+        }
+        addIfCondition(root, {
+          exp: element.elseif,
+          block: element
+        })
+      } else if (process.env.NODE_ENV !== 'production') {
+        warnOnce(
+          `Component template should contain exactly one root element. ` +
+          `If you are using v-if on multiple elements, ` +
+          `use v-else-if to chain them instead.`,
+          { start: element.start }
+        )
+      }
+    }
+    if (currentParent && !element.forbidden) {
+      if (element.elseif || element.else) {
+        processIfConditions(element, currentParent)
+      } else if (element.slotScope) { // scoped slot
+        const name = element.slotTarget || '"default"'
+        ;(currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element
+      } else {
+        currentParent.children.push(element)
+        element.parent = currentParent
+      }
+    }
     // check pre state
     // check pre state
     if (element.pre) {
     if (element.pre) {
       inVPre = false
       inVPre = false
@@ -110,6 +144,23 @@ export function parse (
     }
     }
   }
   }
 
 
+  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']
+      )
+    }
+  }
+
   parseHTML(template, {
   parseHTML(template, {
     warn,
     warn,
     expectHTML: options.expectHTML,
     expectHTML: options.expectHTML,
@@ -174,62 +225,15 @@ export function parse (
         processFor(element)
         processFor(element)
         processIf(element)
         processIf(element)
         processOnce(element)
         processOnce(element)
-        // element-scope stuff
-        processElement(element, options)
       }
       }
 
 
-      function checkRootConstraints (el) {
-        if (process.env.NODE_ENV !== 'production') {
-          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']
-            )
-          }
-        }
-      }
-
-      // tree management
       if (!root) {
       if (!root) {
         root = element
         root = element
-        checkRootConstraints(root)
-      } else if (!stack.length) {
-        // allow root elements with v-if, v-else-if and v-else
-        if (root.if && (element.elseif || element.else)) {
-          checkRootConstraints(element)
-          addIfCondition(root, {
-            exp: element.elseif,
-            block: element
-          })
-        } else if (process.env.NODE_ENV !== 'production') {
-          warnOnce(
-            `Component template should contain exactly one root element. ` +
-            `If you are using v-if on multiple elements, ` +
-            `use v-else-if to chain them instead.`,
-            { start: element.start }
-          )
-        }
-      }
-      if (currentParent && !element.forbidden) {
-        if (element.elseif || element.else) {
-          processIfConditions(element, currentParent)
-        } else if (element.slotScope) { // scoped slot
-          currentParent.plain = false
-          const name = element.slotTarget || '"default"'
-          ;(currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element
-        } else {
-          currentParent.children.push(element)
-          element.parent = currentParent
+        if (process.env.NODE_ENV !== 'production') {
+          checkRootConstraints(root)
         }
         }
       }
       }
+
       if (!unary) {
       if (!unary) {
         currentParent = element
         currentParent = element
         stack.push(element)
         stack.push(element)
@@ -370,20 +374,29 @@ function processRawAttrs (el) {
   }
   }
 }
 }
 
 
-export function processElement (element: ASTElement, options: CompilerOptions) {
+export function processElement (
+  element: ASTElement,
+  options: CompilerOptions,
+  parent: ASTElement | undefined
+) {
   processKey(element)
   processKey(element)
 
 
   // determine whether this is a plain element after
   // determine whether this is a plain element after
   // removing structural attributes
   // removing structural attributes
-  element.plain = !element.key && !element.attrsList.length
+  element.plain = (
+    !element.key &&
+    !element.scopedSlots &&
+    !element.attrsList.length
+  )
 
 
   processRef(element)
   processRef(element)
-  processSlot(element)
+  processSlot(element, parent)
   processComponent(element)
   processComponent(element)
   for (let i = 0; i < transforms.length; i++) {
   for (let i = 0; i < transforms.length; i++) {
     element = transforms[i](element, options) || element
     element = transforms[i](element, options) || element
   }
   }
   processAttrs(element)
   processAttrs(element)
+  return element
 }
 }
 
 
 function processKey (el) {
 function processKey (el) {