Skip to content

Commit 53a0d71

Browse files
committed
fix(compiler): nested scoped slot not update (fix 12232, #12245)
1 parent 9b4e179 commit 53a0d71

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

src/compiler/codegen/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,14 @@ function containsSlotChild(el: ASTNode): boolean {
460460
if (el.tag === 'slot') {
461461
return true
462462
}
463-
return el.children.some(containsSlotChild)
463+
// #12232, #12245: nested scoped slot should update
464+
const childrenIsDynamic = el.children.some(containsSlotChild)
465+
if (childrenIsDynamic) {
466+
return childrenIsDynamic
467+
} else if (el.scopedSlots) {
468+
const scopedSlots = el.scopedSlots
469+
return Object.keys(scopedSlots).some(key => containsSlotChild(scopedSlots[key]))
470+
}
464471
}
465472
return false
466473
}

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

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

1080+
// #12232, #12245
1081+
it('nested named scoped slots should update', done => {
1082+
const initialText = 'initial'
1083+
const scopedSlotContent = 'scopedSlot'
1084+
1085+
const inner = {
1086+
template: `<div><slot v-bind="{ user: '${scopedSlotContent}' }"/></div>`
1087+
}
1088+
1089+
const innerContainer = {
1090+
template: `<div><slot name="content"/></div>`
1091+
}
1092+
1093+
const wrapper = {
1094+
components: { inner, innerContainer },
1095+
name: 'wrapper',
1096+
template: `
1097+
<inner v-slot="{ user }">
1098+
<innerContainer>
1099+
<template #content>
1100+
<div>
1101+
<span>{{ user }}</span>
1102+
<slot/>
1103+
</div>
1104+
</template>
1105+
</innerContainer>
1106+
</inner>
1107+
`
1108+
}
1109+
1110+
const outer = {
1111+
components: { wrapper },
1112+
template: `
1113+
<wrapper>
1114+
<form>
1115+
<span>{{ text }}</span>
1116+
<input v-model="text" type="text"/>
1117+
</form>
1118+
</wrapper>
1119+
`,
1120+
data() {
1121+
return {
1122+
text: initialText,
1123+
}
1124+
},
1125+
}
1126+
1127+
const vm = new Vue({
1128+
components: { outer },
1129+
template: `<outer ref="outer"></outer>`
1130+
}).$mount()
1131+
1132+
expect(vm.$el.textContent).toBe(`${scopedSlotContent} ${initialText} `)
1133+
1134+
const newValue = 'newValue'
1135+
vm.$refs.outer.text = newValue
1136+
const input = vm.$el.querySelector('input')
1137+
input.value = newValue
1138+
triggerEvent(input, 'input')
1139+
1140+
waitForUpdate(() => {
1141+
expect(vm.$el.textContent).toBe(`${scopedSlotContent} ${newValue} `)
1142+
expect(input.value).toBe(newValue)
1143+
}).then(done)
1144+
})
1145+
10801146
it('dynamic v-bind arguments on <slot>', done => {
10811147
const Foo = {
10821148
data() {

0 commit comments

Comments
 (0)