Skip to content

Commit f17a0ce

Browse files
Doctor-wusxzz
authored andcommitted
feat(runtime-vapor): fix slots level
1 parent c749af6 commit f17a0ce

File tree

2 files changed

+127
-19
lines changed

2 files changed

+127
-19
lines changed

Diff for: packages/runtime-vapor/__tests__/componentSlots.spec.ts

+68-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import {
44
type ComponentInternalInstance,
55
createComponent,
6+
createFor,
67
createForSlots,
78
createSlot,
89
createVaporApp,
@@ -15,6 +16,7 @@ import {
1516
renderEffect,
1617
setText,
1718
template,
19+
useSlots,
1820
withDestructure,
1921
} from '../src'
2022
import { makeRender } from './_utils'
@@ -326,7 +328,71 @@ describe('component: slots', () => {
326328
expect(instance.slots).not.toHaveProperty('1')
327329
})
328330

329-
test('dynamicSlots should not cover high weight static slots', async () => {
331+
test('should not delete new rendered slot when the old slot is removed in loop slot', async () => {
332+
const loop = ref([1, 'default', 3])
333+
334+
let childInstance
335+
const t0 = template('<div></div>')
336+
const { component: Child } = define({
337+
setup() {
338+
childInstance = getCurrentInstance()
339+
const slots = useSlots()
340+
const keys = () => Object.keys(slots)
341+
return {
342+
keys,
343+
slots,
344+
}
345+
},
346+
render: (_ctx: any) => {
347+
const n0 = createFor(
348+
() => _ctx.keys(),
349+
(_ctx0: any) => {
350+
const n5 = t0()
351+
const n4 = createSlot(() => _ctx0[0])
352+
insert(n4, n5 as ParentNode)
353+
return n5
354+
},
355+
)
356+
return n0
357+
},
358+
})
359+
360+
const t1 = template(' static default ')
361+
const { render } = define({
362+
setup() {
363+
return createComponent(Child, {}, [
364+
{
365+
default: () => {
366+
return t1()
367+
},
368+
},
369+
() =>
370+
createForSlots(loop.value, (item, i) => ({
371+
name: item,
372+
fn: () => template(item)(),
373+
})),
374+
])
375+
},
376+
})
377+
const { html } = render()
378+
379+
expect(childInstance!.slots).toHaveProperty('1')
380+
expect(childInstance!.slots).toHaveProperty('default')
381+
expect(childInstance!.slots).toHaveProperty('3')
382+
expect(html()).toBe(
383+
'<div>1<!--slot--></div><div>3<!--slot--></div><div>default<!--slot--></div><!--for-->',
384+
)
385+
loop.value = [1]
386+
await nextTick()
387+
expect(childInstance!.slots).toHaveProperty('1')
388+
expect(childInstance!.slots).toHaveProperty('default')
389+
expect(childInstance!.slots).not.toHaveProperty('3')
390+
expect(html()).toBe(
391+
'<div>1<!--slot--></div><div> static default <!--slot--></div><!--for-->',
392+
)
393+
})
394+
395+
test('dynamicSlots should not cover high level slots', async () => {
330396
const dynamicFlag = ref(true)
331397

332398
let instance: ComponentInternalInstance
@@ -343,7 +409,7 @@ describe('component: slots', () => {
343409
() =>
344410
dynamicFlag.value
345411
? { name: 'default', fn: () => template('dynamic default')() }
346-
: { name: 'others', fn: () => template('ohters')() },
412+
: { name: 'others', fn: () => template('others')() },
347413
{
348414
default: () => template('default')(),
349415
},

Diff for: packages/runtime-vapor/src/componentSlots.ts

+59-17
Original file line numberDiff line numberDiff line change
@@ -45,51 +45,93 @@ export function initSlots(
4545
// with ctx
4646
const slots = rawSlots[0] as StaticSlots
4747
for (const name in slots) {
48-
registerSlot(name, slots[name])
48+
resolveSlot(name, slots[name])
4949
}
5050
return
5151
}
5252

5353
instance.slots = shallowReactive({})
54-
const keys: Set<string>[] = []
54+
const renderedSlotKeys: Set<string>[] = []
55+
const slotNameLevels: Record<string, [number, Slot][]> = {}
5556
rawSlots.forEach((slots, index) => {
5657
const isDynamicSlot = isDynamicSlotFn(slots)
5758
if (isDynamicSlot) {
5859
firstEffect(instance, () => {
59-
const recordNames = keys[index] || (keys[index] = new Set())
60+
const renderedKeys =
61+
renderedSlotKeys[index] || (renderedSlotKeys[index] = new Set())
6062
let dynamicSlot: ReturnType<DynamicSlotFn>
61-
if (isDynamicSlotFn(slots)) {
62-
dynamicSlot = slots()
63-
if (isArray(dynamicSlot)) {
64-
for (const slot of dynamicSlot) {
65-
registerSlot(slot.name, slot.fn, recordNames)
66-
}
67-
} else if (dynamicSlot) {
68-
registerSlot(dynamicSlot.name, dynamicSlot.fn, recordNames)
63+
dynamicSlot = slots()
64+
const restoreKeys = cleanupSlot(index)
65+
if (isArray(dynamicSlot)) {
66+
for (const slot of dynamicSlot) {
67+
registerSlot(slot.name, slot.fn, index, renderedKeys)
68+
}
69+
} else if (dynamicSlot) {
70+
registerSlot(dynamicSlot.name, dynamicSlot.fn, index, renderedKeys)
71+
}
72+
if (restoreKeys.length) {
73+
for (const key of restoreKeys) {
74+
resolveSlot(key, slotNameLevels[key][0][1])
6975
}
70-
} else {
7176
}
72-
for (const name of recordNames) {
77+
for (const name of renderedKeys) {
7378
if (
7479
!(isArray(dynamicSlot)
7580
? dynamicSlot.some(s => s.name === name)
7681
: dynamicSlot && dynamicSlot.name === name)
7782
) {
78-
recordNames.delete(name)
83+
renderedKeys.delete(name)
7984
delete instance.slots[name]
8085
}
8186
}
8287
})
8388
} else {
8489
for (const name in slots) {
85-
registerSlot(name, slots[name])
90+
registerSlot(name, slots[name], index)
8691
}
8792
}
8893
})
8994

90-
function registerSlot(name: string, fn: Slot, recordNames?: Set<string>) {
95+
function cleanupSlot(level: number) {
96+
const restoreKeys: string[] = []
97+
Object.keys(slotNameLevels).forEach(key => {
98+
const index = slotNameLevels[key].findIndex(([l]) => l === level)
99+
if (index > -1) {
100+
slotNameLevels[key].splice(index, 1)
101+
if (!slotNameLevels[key].length) {
102+
delete slotNameLevels[key]
103+
return
104+
}
105+
if (index === 0) {
106+
renderedSlotKeys[level] && renderedSlotKeys[level].delete(key)
107+
restoreKeys.push(key)
108+
}
109+
}
110+
})
111+
return restoreKeys
112+
}
113+
114+
function registerSlot(
115+
name: string,
116+
fn: Slot,
117+
level: number,
118+
renderedKeys?: Set<string>,
119+
) {
120+
slotNameLevels[name] = slotNameLevels[name] || []
121+
slotNameLevels[name].push([level, fn])
122+
slotNameLevels[name].sort((a, b) => b[0] - a[0])
123+
for (let i = 1; i < slotNameLevels[name].length; i++) {
124+
const hidenLevel = slotNameLevels[name][i][0]
125+
renderedSlotKeys[hidenLevel] && renderedSlotKeys[hidenLevel].delete(name)
126+
}
127+
if (slotNameLevels[name][0][0] === level) {
128+
renderedKeys && renderedKeys.add(name)
129+
}
130+
resolveSlot(name, slotNameLevels[name][0][1])
131+
}
132+
133+
function resolveSlot(name: string, fn: Slot) {
91134
instance.slots[name] = withCtx(fn)
92-
recordNames && recordNames.add(name)
93135
}
94136

95137
function withCtx(fn: Slot): Slot {

0 commit comments

Comments
 (0)