Skip to content

Commit bab9eaa

Browse files
committed
fix(compat): do not auto invoke scoped slots when accessed via $slots
1 parent c0c9432 commit bab9eaa

File tree

2 files changed

+48
-1
lines changed

2 files changed

+48
-1
lines changed

packages/runtime-core/src/compat/componentFunctional.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
getCurrentInstance,
55
} from '../component'
66
import { resolveInjections } from '../componentOptions'
7+
import type { ContextualRenderFn } from '../componentRenderContext'
78
import type { InternalSlots } from '../componentSlots'
89
import { getCompatListeners } from './instanceListeners'
910
import { compatH } from './renderFn'
@@ -15,7 +16,10 @@ const normalizedFunctionalComponentMap = new WeakMap<
1516
export const legacySlotProxyHandlers: ProxyHandler<InternalSlots> = {
1617
get(target, key: string) {
1718
const slot = target[key]
18-
return slot && slot()
19+
return (
20+
slot &&
21+
((slot as ContextualRenderFn)._ns /* non-scoped slot */ ? slot() : slot)
22+
)
1923
},
2024
}
2125

packages/vue-compat/__tests__/instance.spec.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,49 @@ describe('INSTANCE_SCOPED_SLOTS', () => {
309309
})
310310
})
311311

312+
describe('RENDER_FUNCTION', () => {
313+
test('should not auto invoke scoped slot accessed via $slots in a render function', () => {
314+
new Vue({
315+
template: `<child v-slot="{ msg }">{{ msg }}</child>`,
316+
components: {
317+
child: {
318+
compatConfig: { MODE: 2 },
319+
render() {
320+
expect(() => this.$slots.default).not.toThrow()
321+
expect(this.$slots.default).toBeTypeOf('function')
322+
},
323+
},
324+
},
325+
}).$mount()
326+
327+
expect(
328+
deprecationData[DeprecationTypes.RENDER_FUNCTION].message,
329+
).toHaveBeenWarned()
330+
})
331+
332+
test('should auto invoke non-scoped slot accessed via $slots in a render function', () => {
333+
const DEFAULT_SLOT_CONTENTS = 'foo'
334+
335+
new Vue({
336+
template: `<child>${DEFAULT_SLOT_CONTENTS}</child>`,
337+
components: {
338+
child: {
339+
compatConfig: { MODE: 2 },
340+
render() {
341+
expect(this.$slots.default[0].children).toEqual(
342+
DEFAULT_SLOT_CONTENTS,
343+
)
344+
},
345+
},
346+
},
347+
}).$mount()
348+
349+
expect(
350+
deprecationData[DeprecationTypes.RENDER_FUNCTION].message,
351+
).toHaveBeenWarned()
352+
})
353+
})
354+
312355
test('INSTANCE_ATTR_CLASS_STYLE', () => {
313356
const vm = new Vue({
314357
template: `<child class="foo" style="color:red" id="ok" />`,

0 commit comments

Comments
 (0)