|
|
@@ -20,7 +20,11 @@ import {
|
|
|
isHydrating,
|
|
|
locateHydrationNode,
|
|
|
} from './dom/hydration'
|
|
|
-import { SlotFragment, type VaporFragment } from './fragment'
|
|
|
+import {
|
|
|
+ type DynamicFragment,
|
|
|
+ SlotFragment,
|
|
|
+ type VaporFragment,
|
|
|
+} from './fragment'
|
|
|
import { createElement } from './dom/node'
|
|
|
import { setDynamicProps } from './dom/prop'
|
|
|
|
|
|
@@ -96,7 +100,9 @@ export const dynamicSlotsProxyHandlers: ProxyHandler<RawSlots> = {
|
|
|
export function getSlot(
|
|
|
target: RawSlots,
|
|
|
key: string,
|
|
|
-): (VaporSlot & { _bound?: VaporSlot }) | undefined {
|
|
|
+):
|
|
|
+ | (VaporSlot & { _boundMap?: WeakMap<DynamicFragment, VaporSlot> })
|
|
|
+ | undefined {
|
|
|
if (key === '$') return
|
|
|
const dynamicSources = target.$
|
|
|
if (dynamicSources) {
|
|
|
@@ -237,25 +243,29 @@ export function createSlot(
|
|
|
|
|
|
const slot = getSlot(rawSlots, slotName)
|
|
|
if (slot) {
|
|
|
- // Create and cache bound version of the slot to make it stable
|
|
|
- // so that we avoid unnecessary updates if it resolves to the same slot
|
|
|
- fragment.updateSlot(
|
|
|
- slot._bound ||
|
|
|
- (slot._bound = () => {
|
|
|
- const prevSlotScopeIds = setCurrentSlotScopeIds(
|
|
|
- slotScopeIds.length > 0 ? slotScopeIds : null,
|
|
|
- )
|
|
|
- const prev = inOnceSlot
|
|
|
- try {
|
|
|
- if (once) inOnceSlot = true
|
|
|
- return slot(slotProps)
|
|
|
- } finally {
|
|
|
- inOnceSlot = prev
|
|
|
- setCurrentSlotScopeIds(prevSlotScopeIds)
|
|
|
- }
|
|
|
- }),
|
|
|
- fallback,
|
|
|
- )
|
|
|
+ // Create and cache bound slot to keep it stable and avoid unnecessary
|
|
|
+ // updates when it resolves to the same slot. Cache per-fragment
|
|
|
+ // (v-for creates multiple fragments) so each fragment keeps its own
|
|
|
+ // slotProps without cross-talk.
|
|
|
+ const boundMap = slot._boundMap || (slot._boundMap = new WeakMap())
|
|
|
+ let bound = boundMap.get(fragment)
|
|
|
+ if (!bound) {
|
|
|
+ bound = () => {
|
|
|
+ const prevSlotScopeIds = setCurrentSlotScopeIds(
|
|
|
+ slotScopeIds.length > 0 ? slotScopeIds : null,
|
|
|
+ )
|
|
|
+ const prev = inOnceSlot
|
|
|
+ try {
|
|
|
+ if (once) inOnceSlot = true
|
|
|
+ return slot(slotProps)
|
|
|
+ } finally {
|
|
|
+ inOnceSlot = prev
|
|
|
+ setCurrentSlotScopeIds(prevSlotScopeIds)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ boundMap.set(fragment, bound)
|
|
|
+ }
|
|
|
+ fragment.updateSlot(bound, fallback)
|
|
|
} else {
|
|
|
fragment.updateSlot(undefined, fallback)
|
|
|
}
|