mirror of https://github.com/vuejs/core.git
feat(runtime-vapor): attach current instance to render slot (#168)
This commit is contained in:
parent
db140a1e37
commit
9a33d79963
|
@ -34,21 +34,6 @@ function renderWithSlots(slots: any): any {
|
|||
}
|
||||
|
||||
describe('component: slots', () => {
|
||||
test('initSlots: instance.slots should be set correctly', () => {
|
||||
const { slots } = renderWithSlots({ _: 1 })
|
||||
expect(slots).toMatchObject({ _: 1 })
|
||||
})
|
||||
|
||||
// NOTE: slot normalization is not supported
|
||||
test.todo(
|
||||
'initSlots: should normalize object slots (when value is null, string, array)',
|
||||
() => {},
|
||||
)
|
||||
test.todo(
|
||||
'initSlots: should normalize object slots (when value is function)',
|
||||
() => {},
|
||||
)
|
||||
|
||||
test('initSlots: instance.slots should be set correctly', () => {
|
||||
let instance: any
|
||||
const Comp = defineComponent({
|
||||
|
@ -73,6 +58,16 @@ describe('component: slots', () => {
|
|||
)
|
||||
})
|
||||
|
||||
// NOTE: slot normalization is not supported
|
||||
test.todo(
|
||||
'initSlots: should normalize object slots (when value is null, string, array)',
|
||||
() => {},
|
||||
)
|
||||
test.todo(
|
||||
'initSlots: should normalize object slots (when value is function)',
|
||||
() => {},
|
||||
)
|
||||
|
||||
// runtime-core's "initSlots: instance.slots should be set correctly (when vnode.shapeFlag is not SLOTS_CHILDREN)"
|
||||
test('initSlots: instance.slots should be set correctly', () => {
|
||||
const { slots } = renderWithSlots({
|
||||
|
@ -152,6 +147,60 @@ describe('component: slots', () => {
|
|||
expect(instance.slots).toHaveProperty('footer')
|
||||
})
|
||||
|
||||
test('the current instance should be kept in the slot', async () => {
|
||||
let instanceInDefaultSlot: any
|
||||
let instanceInVForSlot: any
|
||||
let instanceInVIfSlot: any
|
||||
|
||||
const Comp = defineComponent({
|
||||
render() {
|
||||
const instance = getCurrentInstance()
|
||||
instance!.slots.default!()
|
||||
instance!.slots.inVFor!()
|
||||
instance!.slots.inVIf!()
|
||||
return template('<div></div>')()
|
||||
},
|
||||
})
|
||||
|
||||
const { instance } = define({
|
||||
render() {
|
||||
return createComponent(
|
||||
Comp,
|
||||
{},
|
||||
{
|
||||
default: () => {
|
||||
instanceInDefaultSlot = getCurrentInstance()
|
||||
return template('content')()
|
||||
},
|
||||
},
|
||||
() => [
|
||||
[
|
||||
{
|
||||
name: 'inVFor',
|
||||
fn: () => {
|
||||
instanceInVForSlot = getCurrentInstance()
|
||||
return template('content')()
|
||||
},
|
||||
},
|
||||
],
|
||||
{
|
||||
name: 'inVIf',
|
||||
key: '1',
|
||||
fn: () => {
|
||||
instanceInVIfSlot = getCurrentInstance()
|
||||
return template('content')()
|
||||
},
|
||||
},
|
||||
],
|
||||
)
|
||||
},
|
||||
}).render()
|
||||
|
||||
expect(instanceInDefaultSlot).toBe(instance)
|
||||
expect(instanceInVForSlot).toBe(instance)
|
||||
expect(instanceInVIfSlot).toBe(instance)
|
||||
})
|
||||
|
||||
test.todo('should respect $stable flag', async () => {
|
||||
// TODO: $stable flag?
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { type IfAny, extend, isArray } from '@vue/shared'
|
||||
import { type IfAny, isArray } from '@vue/shared'
|
||||
import { baseWatch } from '@vue/reactivity'
|
||||
import type { ComponentInternalInstance } from './component'
|
||||
import { type ComponentInternalInstance, setCurrentInstance } from './component'
|
||||
import type { Block } from './apiRender'
|
||||
import { createVaporPreScheduler } from './scheduler'
|
||||
|
||||
|
@ -29,7 +29,14 @@ export const initSlots = (
|
|||
rawSlots: InternalSlots | null = null,
|
||||
dynamicSlots: DynamicSlots | null = null,
|
||||
) => {
|
||||
const slots: InternalSlots = extend({}, rawSlots)
|
||||
const slots: InternalSlots = {}
|
||||
|
||||
for (const key in rawSlots) {
|
||||
const slot = rawSlots[key]
|
||||
if (slot) {
|
||||
slots[key] = withCtx(slot)
|
||||
}
|
||||
}
|
||||
|
||||
if (dynamicSlots) {
|
||||
const dynamicSlotKeys: Record<string, true> = {}
|
||||
|
@ -41,12 +48,13 @@ export const initSlots = (
|
|||
// array of dynamic slot generated by <template v-for="..." #[...]>
|
||||
if (isArray(slot)) {
|
||||
for (let j = 0; j < slot.length; j++) {
|
||||
slots[slot[j].name] = slot[j].fn
|
||||
slots[slot[j].name] = withCtx(slot[j].fn)
|
||||
dynamicSlotKeys[slot[j].name] = true
|
||||
}
|
||||
} else if (slot) {
|
||||
// conditional single slot generated by <template v-if="..." #foo>
|
||||
slots[slot.name] = slot.key
|
||||
slots[slot.name] = withCtx(
|
||||
slot.key
|
||||
? (...args: any[]) => {
|
||||
const res = slot.fn(...args)
|
||||
// attach branch key so each conditional branch is considered a
|
||||
|
@ -54,7 +62,8 @@ export const initSlots = (
|
|||
if (res) (res as any).key = slot.key
|
||||
return res
|
||||
}
|
||||
: slot.fn
|
||||
: slot.fn,
|
||||
)
|
||||
dynamicSlotKeys[slot.name] = true
|
||||
}
|
||||
}
|
||||
|
@ -77,4 +86,15 @@ export const initSlots = (
|
|||
}
|
||||
|
||||
instance.slots = slots
|
||||
|
||||
function withCtx(fn: Slot): Slot {
|
||||
return (...args: any[]) => {
|
||||
const reset = setCurrentInstance(instance.parent!)
|
||||
try {
|
||||
return fn(...args)
|
||||
} finally {
|
||||
reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue