Skip to content

Commit 99f3774

Browse files
committed
improve implicit fragment instance handling (fix #1084)
1 parent 46c9f9c commit 99f3774

File tree

4 files changed

+54
-10
lines changed

4 files changed

+54
-10
lines changed

src/compiler/transclude.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,21 @@ function transcludeTemplate (el, options) {
7171
'should probably use `replace: false` here.'
7272
)
7373
}
74+
// there are many cases where the instance must
75+
// become a fragment instance: basically anything that
76+
// can create more than 1 root nodes.
7477
if (
7578
// multi-children template
7679
frag.childNodes.length > 1 ||
7780
// non-element template
7881
replacer.nodeType !== 1 ||
79-
// when root node is <component>, is an element
80-
// directive, or has v-repeat, the instance could
81-
// end up having multiple top-level nodes, thus
82-
// becoming a block instance.
82+
// single nested component
8383
tag === 'component' ||
84+
_.resolveAsset(options, 'components', tag) ||
85+
replacer.hasAttribute(config.prefix + 'component') ||
86+
// element directive
8487
_.resolveAsset(options, 'elementDirectives', tag) ||
88+
// repeat block
8589
replacer.hasAttribute(config.prefix + 'repeat')
8690
) {
8791
return frag

src/directives/component.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,8 @@ module.exports = {
5151
}
5252
} else {
5353
process.env.NODE_ENV !== 'production' && _.warn(
54-
'Do not create a component that only contains ' +
55-
'a single other component - they will be mounted to ' +
56-
'the same element and cause conflict. Wrap it with ' +
57-
'an outer element.'
54+
'cannot mount component "' + this.expression + '" ' +
55+
'on already mounted element: ' + this.el
5856
)
5957
}
6058
},

test/unit/specs/compiler/transclude_spec.js

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,49 @@ if (_.inBrowser) {
4242
expect(res.innerHTML).toBe('{{hi}}')
4343
})
4444

45-
it('block instance', function () {
45+
it('template replace -> fragment instance', function () {
46+
var res
47+
options.replace = true
48+
49+
// multiple root
50+
options.template = '<div></div><div></div>'
51+
res = transclude(el, options)
52+
expect(res instanceof DocumentFragment).toBe(true)
53+
54+
// non-element
55+
options.template = '{{hi}}'
56+
res = transclude(el, options)
57+
expect(res instanceof DocumentFragment).toBe(true)
58+
59+
// single component: <component>
60+
options.template = '<component is="{{hi}}"></component>'
61+
res = transclude(el, options)
62+
expect(res instanceof DocumentFragment).toBe(true)
63+
64+
// single component: custom element
65+
options.template = '<test></test>'
66+
options.components = { test: {}}
67+
res = transclude(el, options)
68+
expect(res instanceof DocumentFragment).toBe(true)
69+
70+
// single component: v-component
71+
options.template = '<div v-component="test"></div>'
72+
res = transclude(el, options)
73+
expect(res instanceof DocumentFragment).toBe(true)
74+
75+
// element directive
76+
options.template = '<el-dir></el-dir>'
77+
options.elementDirectives = { 'el-dir': {}}
78+
res = transclude(el, options)
79+
expect(res instanceof DocumentFragment).toBe(true)
80+
81+
// v-repeat
82+
options.template = '<div v-repeat="list"></div>'
83+
res = transclude(el, options)
84+
expect(res instanceof DocumentFragment).toBe(true)
85+
})
86+
87+
it('direct fragment instance', function () {
4688
var frag = document.createDocumentFragment()
4789
frag.appendChild(el)
4890
var res = transclude(frag, options)

test/unit/specs/directives/component_spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ if (_.inBrowser) {
420420
new Vue({
421421
el: el
422422
})
423-
expect(hasWarned(_, 'Do not create a component that only contains a single other component')).toBe(true)
423+
expect(hasWarned(_, 'cannot mount component "test" on already mounted element')).toBe(true)
424424
})
425425

426426
})

0 commit comments

Comments
 (0)