Skip to content

Commit

Permalink
fix: ensure scoped slot containing passed down slot content updates p…
Browse files Browse the repository at this point in the history
…roperly
  • Loading branch information
yyx990803 committed Feb 11, 2019
1 parent 11deaa9 commit 21fca2f
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 2 deletions.
17 changes: 16 additions & 1 deletion src/compiler/codegen/index.js
Expand Up @@ -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
Expand All @@ -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
Expand Down
29 changes: 28 additions & 1 deletion test/unit/features/component/component-scoped-slot.spec.js
Expand Up @@ -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>`
}
Expand Down Expand Up @@ -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)
})
})

0 comments on commit 21fca2f

Please sign in to comment.