Browse Source

extract slots from template content (fix #2435)

Evan You 10 years ago
parent
commit
ccd11fb095
3 changed files with 54 additions and 2 deletions
  1. 24 2
      src/compiler/scan-slots.js
  2. 6 0
      src/util/env.js
  3. 24 0
      test/unit/specs/directives/element/slot_spec.js

+ 24 - 2
src/compiler/scan-slots.js

@@ -3,7 +3,8 @@ import {
   isTemplate,
   toArray,
   getBindAttr,
-  warn
+  warn,
+  hasNativeTemplate
 } from '../util/index'
 
 /**
@@ -22,7 +23,7 @@ export function scanSlots (template, content, vm) {
     return
   }
   var contents = vm._slotContents = {}
-  var slots = template.querySelectorAll('slot')
+  var slots = findSlots(template)
   if (slots.length) {
     var hasDefault, slot, name
     for (var i = 0, l = slots.length; i < l; i++) {
@@ -56,6 +57,27 @@ export function scanSlots (template, content, vm) {
   }
 }
 
+/**
+ * Find all slots in a template, including those nested under
+ * a <template> element's content node.
+ *
+ * @param {Element} el
+ * @return {Array|NodeList}
+ */
+
+function findSlots (el) {
+  var slots = el.querySelectorAll('slot')
+  /* istanbul ignore if */
+  if (hasNativeTemplate) {
+    slots = toArray(slots)
+    var templates = el.querySelectorAll('template')
+    for (var i = 0; i < templates.length; i++) {
+      slots.push.apply(slots, findSlots(templates[i].content))
+    }
+  }
+  return slots
+}
+
 /**
  * Extract qualified content nodes from a node list.
  *

+ 6 - 0
src/util/env.js

@@ -8,6 +8,12 @@ export const inBrowser =
   typeof window !== 'undefined' &&
   Object.prototype.toString.call(window) !== '[object Object]'
 
+// Check if the browser supports native <template>.
+export const hasNativeTemplate = (function () {
+  var t = document.createElement('template')
+  return t.content && t.content.nodeType === 11
+})()
+
 // detect devtools
 export const devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__
 

+ 24 - 0
test/unit/specs/directives/element/slot_spec.js

@@ -406,4 +406,28 @@ describe('Slot Distribution', function () {
       done()
     })
   })
+
+  // #2435
+  it('slot inside template', function () {
+    var vm = new Vue({
+      el: el,
+      template: '<test>hi</test>',
+      components: {
+        test: {
+          data: function () {
+            return { ok: true }
+          },
+          template:
+            '<div>' +
+              '<template v-if="ok">' +
+                '<template v-if="ok">' +
+                  '<slot>{{ msg }}</slot>' +
+                '</template>' +
+              '</template>' +
+            '</div>'
+        }
+      }
+    })
+    expect(vm.$el.textContent).toBe('hi')
+  })
 })