Skip to content

Commit 041f514

Browse files
committed
fix(compiler): nested scoped slot not update (fix 12232, #12245)
1 parent 7094fc0 commit 041f514

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

src/compiler/codegen/index.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,14 @@ function containsSlotChild (el: ASTNode): boolean {
430430
if (el.tag === 'slot') {
431431
return true
432432
}
433-
return el.children.some(containsSlotChild)
433+
// #12232, #12245: nested scoped slot should update
434+
const childrenIsDynamic = el.children.some(containsSlotChild)
435+
if (childrenIsDynamic) {
436+
return childrenIsDynamic
437+
} else if (el.scopedSlots) {
438+
const scopedSlots = el.scopedSlots
439+
return Object.keys(scopedSlots).some(key => containsSlotChild(scopedSlots[key]))
440+
}
434441
}
435442
return false
436443
}

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

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,72 @@ describe('Component scoped slot', () => {
10261026
}).then(done)
10271027
})
10281028

1029+
// #12232, #12245
1030+
it('nested named scoped slots should update', done => {
1031+
const initialText = 'initial'
1032+
const scopedSlotContent = 'scopedSlot'
1033+
1034+
const inner = {
1035+
template: `<div><slot v-bind="{ user: '${scopedSlotContent}' }"/></div>`
1036+
}
1037+
1038+
const innerContainer = {
1039+
template: `<div><slot name="content"/></div>`
1040+
}
1041+
1042+
const wrapper = {
1043+
components: { inner, innerContainer },
1044+
name: 'wrapper',
1045+
template: `
1046+
<inner v-slot="{ user }">
1047+
<innerContainer>
1048+
<template #content>
1049+
<div>
1050+
<span>{{ user }}</span>
1051+
<slot/>
1052+
</div>
1053+
</template>
1054+
</innerContainer>
1055+
</inner>
1056+
`
1057+
}
1058+
1059+
const outer = {
1060+
components: { wrapper },
1061+
template: `
1062+
<wrapper>
1063+
<form>
1064+
<span>{{ text }}</span>
1065+
<input v-model="text" type="text"/>
1066+
</form>
1067+
</wrapper>
1068+
`,
1069+
data() {
1070+
return {
1071+
text: initialText,
1072+
}
1073+
},
1074+
}
1075+
1076+
const vm = new Vue({
1077+
components: { outer },
1078+
template: `<outer ref="outer"></outer>`
1079+
}).$mount()
1080+
1081+
expect(vm.$el.textContent).toBe(`${scopedSlotContent} ${initialText} `)
1082+
1083+
const newValue = 'newValue'
1084+
vm.$refs.outer.text = newValue
1085+
const input = vm.$el.querySelector('input')
1086+
input.value = newValue
1087+
triggerEvent(input, 'input')
1088+
1089+
waitForUpdate(() => {
1090+
expect(vm.$el.textContent).toBe(`${scopedSlotContent} ${newValue} `)
1091+
expect(input.value).toBe(newValue)
1092+
}).then(done)
1093+
})
1094+
10291095
it('dynamic v-bind arguments on <slot>', done => {
10301096
const Foo = {
10311097
data() {

0 commit comments

Comments
 (0)