Skip to content

Commit 3e06c57

Browse files
chrisvfritzyyx990803
authored andcommitted
Allow 2 root nodes with v-if and v-else (#3329)
* allow 2 root nodes with v-if and v-else * apply root constraints to 2nd root element with v-else
1 parent 7b3cb27 commit 3e06c57

File tree

2 files changed

+48
-11
lines changed

2 files changed

+48
-11
lines changed

src/compiler/parser/index.js

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -130,29 +130,37 @@ export function parse (
130130
processAttrs(element)
131131
}
132132

133-
// tree management
134-
if (!root) {
135-
root = element
136-
// check root element constraints
133+
function checkRootConstraints (el) {
137134
if (process.env.NODE_ENV !== 'production') {
138-
if (tag === 'slot' || tag === 'template') {
135+
if (el.tag === 'slot' || el.tag === 'template') {
139136
warn(
140-
`Cannot use <${tag}> as component root element because it may ` +
137+
`Cannot use <${el.tag}> as component root element because it may ` +
141138
'contain multiple nodes:\n' + template
142139
)
143140
}
144-
if (element.attrsMap.hasOwnProperty('v-for')) {
141+
if (el.attrsMap.hasOwnProperty('v-for')) {
145142
warn(
146143
'Cannot use v-for on stateful component root element because ' +
147144
'it renders multiple elements:\n' + template
148145
)
149146
}
150147
}
148+
}
149+
150+
// tree management
151+
if (!root) {
152+
root = element
153+
checkRootConstraints(root)
151154
} else if (process.env.NODE_ENV !== 'production' && !stack.length && !warned) {
152-
warned = true
153-
warn(
154-
`Component template should contain exactly one root element:\n\n${template}`
155-
)
155+
// allow 2 root elements with v-if and v-else
156+
if ((root.attrsMap.hasOwnProperty('v-if') && element.attrsMap.hasOwnProperty('v-else'))) {
157+
checkRootConstraints(element)
158+
} else {
159+
warned = true
160+
warn(
161+
`Component template should contain exactly one root element:\n\n${template}`
162+
)
163+
}
156164
}
157165
if (currentParent && !element.forbidden) {
158166
if (element.else) {

test/unit/modules/compiler/parser.spec.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,35 @@ describe('parser', () => {
7676
expect('Component template should contain exactly one root element').toHaveBeenWarned()
7777
})
7878

79+
it('warn multiple root elements', () => {
80+
parse('<div></div><div></div>', baseOptions)
81+
expect('Component template should contain exactly one root element:\n\n<div></div><div></div>').toHaveBeenWarned()
82+
})
83+
84+
it('not warn 2 root elements with v-if and v-else', () => {
85+
parse('<div v-if="1"></div><div v-else></div>', baseOptions)
86+
expect('Component template should contain exactly one root element:\n\n<div v-if="1"></div><div v-else></div>')
87+
.not.toHaveBeenWarned()
88+
})
89+
90+
it('warn 2 root elements with v-if', () => {
91+
parse('<div v-if="1"></div><div v-if="2"></div>', baseOptions)
92+
expect('Component template should contain exactly one root element:\n\n<div v-if="1"></div><div v-if="2"></div>')
93+
.toHaveBeenWarned()
94+
})
95+
96+
it('warn 3 root elements with v-if and v-else on first 2', () => {
97+
parse('<div v-if="1"></div><div v-else></div><div></div>', baseOptions)
98+
expect('Component template should contain exactly one root element:\n\n<div v-if="1"></div><div v-else></div><div></div>')
99+
.toHaveBeenWarned()
100+
})
101+
102+
it('warn 2 root elements with v-if and v-else with v-for on 2nd', () => {
103+
parse('<div v-if="1"></div><div v-else v-for="i in [1]"></div>', baseOptions)
104+
expect('Cannot use v-for on stateful component root element because it renders multiple elements:\n<div v-if="1"></div><div v-else v-for="i in [1]"></div>')
105+
.toHaveBeenWarned()
106+
})
107+
79108
it('warn <template> as root element', () => {
80109
parse('<template></template>', baseOptions)
81110
expect('Cannot use <template> as component root element').toHaveBeenWarned()

0 commit comments

Comments
 (0)