Browse Source

fix: ensure scoped slot containing passed down slot content updates properly

dev
Evan You 6 years ago
parent
commit
21fca2fffc
  1. 17
      src/compiler/codegen/index.js
  2. 29
      test/unit/features/component/component-scoped-slot.spec.js

17
src/compiler/codegen/index.js

@ -368,7 +368,12 @@ function genScopedSlots (
// for example if the slot contains dynamic names, has v-if or v-for on them...
let needsForceUpdate = Object.keys(slots).some(key => {
const slot = slots[key]
return slot.slotTargetDynamic || slot.if || slot.for
return (
slot.slotTargetDynamic ||
slot.if ||
slot.for ||
containsSlotChild(slot) // is passing down slot from parent which may be dynamic
)
})
// OR when it is inside another scoped slot (the reactivity is disconnected)
// #9438
@ -390,6 +395,16 @@ function genScopedSlots (
}]${needsForceUpdate ? `,true` : ``})`
}
function containsSlotChild (el: ASTNode): boolean {
if (el.type === 1) {
if (el.tag === 'slot') {
return true
}
return el.children.some(containsSlotChild)
}
return false
}
function genScopedSlot (
el: ASTElement,
state: CodegenState

29
test/unit/features/component/component-scoped-slot.spec.js

@ -1104,7 +1104,7 @@ describe('Component scoped slot', () => {
expect(vm.$el.textContent).toBe('hello')
})
it('should not cache scoped slot normalzation when there are a mix of normal and scoped slots', done => {
it('should not cache scoped slot normalization when there are a mix of normal and scoped slots', done => {
const foo = {
template: `<div><slot name="foo" /> <slot name="bar" /></div>`
}
@ -1144,4 +1144,31 @@ describe('Component scoped slot', () => {
expect(vm.$el.textContent).toBe('foo bar')
})
it('should not skip updates when a scoped slot contains parent <slot/> content', done => {
const inner = {
template: `<div><slot/></div>`
}
const wrapper = {
template: `<inner v-slot><slot/></inner>`,
components: { inner }
}
const vm = new Vue({
data() {
return {
ok: true
}
},
components: { wrapper },
template: `<wrapper><div>{{ ok ? 'foo' : 'bar' }}</div></wrapper>`
}).$mount()
expect(vm.$el.textContent).toBe('foo')
vm.ok = false
waitForUpdate(() => {
expect(vm.$el.textContent).toBe('bar')
}).then(done)
})
})

Loading…
Cancel
Save