fix: template v-slot should work with v-else conditions

This commit is contained in:
Evan You 2019-01-30 21:30:29 -05:00
parent 5851961ca3
commit 2807fd24b0
3 changed files with 53 additions and 41 deletions

View File

@ -366,53 +366,27 @@ function genScopedSlots (
})
return `scopedSlots:_u([${
Object.keys(slots).map(key => {
return genScopedSlot(key, slots[key], state)
return genScopedSlot(slots[key], state)
}).join(',')
}]${hasDynamicKeys ? `,true` : ``})`
}
function genScopedSlot (
key: string,
el: ASTElement,
state: CodegenState
): string {
if (el.if && !el.ifProcessed) {
return genIfScopedSlot(key, el, state)
return genIf(el, state, genScopedSlot, `null`)
}
if (el.for && !el.forProcessed) {
return genForScopedSlot(key, el, state)
return genFor(el, state, genScopedSlot)
}
const fn = `function(${String(el.slotScope)}){` +
`return ${el.tag === 'template'
? genChildren(el, state) || 'undefined'
: genElement(el, state)
}}`
return `{key:${key},fn:${fn}}`
}
function genIfScopedSlot (
key: string,
el: any,
state: CodegenState
): string {
el.ifProcessed = true
return `(${el.if})?${genScopedSlot(key, el, state)}:null`
}
function genForScopedSlot (
key: string,
el: any,
state: CodegenState
): string {
const exp = el.for
const alias = el.alias
const iterator1 = el.iterator1 ? `,${el.iterator1}` : ''
const iterator2 = el.iterator2 ? `,${el.iterator2}` : ''
el.forProcessed = true // avoid recursion
return `_l((${exp}),` +
`function(${alias}${iterator1}${iterator2}){` +
`return ${genScopedSlot(key, el, state)}` +
'})'
return `{key:${el.slotTarget || `"default"`},fn:${fn}}`
}
export function genChildren (

View File

@ -107,6 +107,7 @@ export function parse (
}
function closeElement (element) {
trimEndingWhitespace(element)
if (!inVPre && !element.processed) {
element = processElement(element, options)
}
@ -133,14 +134,25 @@ export function parse (
if (currentParent && !element.forbidden) {
if (element.elseif || element.else) {
processIfConditions(element, currentParent)
} else if (element.slotScope) { // scoped slot
} else {
if (element.slotScope) {
// scoped slot
// keep it in the children list so that v-else(-if) conditions can
// find it as the prev node.
const name = element.slotTarget || '"default"'
;(currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element
} else {
}
currentParent.children.push(element)
element.parent = currentParent
}
}
// final children cleanup
// filter out scoped slots
element.children = element.children.filter(c => !c.slotScope)
// remove trailing whitespace node again
trimEndingWhitespace(element)
// check pre state
if (element.pre) {
inVPre = false
@ -154,6 +166,20 @@ export function parse (
}
}
function trimEndingWhitespace (el) {
// remove trailing whitespace node
if (!inPre) {
let lastNode
while (
(lastNode = el.children[el.children.length - 1]) &&
lastNode.type === 3 &&
lastNode.text === ' '
) {
el.children.pop()
}
}
}
function checkRootConstraints (el) {
if (el.tag === 'slot' || el.tag === 'template') {
warnOnce(
@ -268,13 +294,6 @@ export function parse (
end (tag, start, end) {
const element = stack[stack.length - 1]
if (!inPre) {
// remove trailing whitespace node
const lastNode = element.children[element.children.length - 1]
if (lastNode && lastNode.type === 3 && lastNode.text === ' ') {
element.children.pop()
}
}
// pop stack
stack.length -= 1
currentParent = stack[stack.length - 1]
@ -658,8 +677,9 @@ function processSlotContent (el) {
const slots = el.scopedSlots || (el.scopedSlots = {})
const { name, dynamic } = getSlotName(slotBinding)
const slotContainer = slots[name] = createASTElement('template', [], el)
slotContainer.slotTarget = name
slotContainer.slotTargetDynamic = dynamic
slotContainer.children = el.children
slotContainer.children = el.children.filter(c => !c.slotScope)
slotContainer.slotScope = slotBinding.value || `_`
// remove children as they are returned from scopedSlots now
el.children = []

View File

@ -827,6 +827,24 @@ describe('Component scoped slot', () => {
expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`b from foo one a from foo two `)
}).then(done)
})
it('should work with v-if/v-else', done => {
const vm = new Vue({
data: { flag: true },
template: `
<foo>
<template v-if="flag" v-slot:one="one">a {{ one }} </template>
<template v-else v-slot:two="two">b {{ two }} </template>
</foo>
`,
components: { Foo }
}).$mount()
expect(vm.$el.innerHTML).toBe(`a from foo one `)
vm.flag = false
waitForUpdate(() => {
expect(vm.$el.innerHTML).toBe(`b from foo two `)
}).then(done)
})
})
// 2.6 scoped slot perf optimization