wip: slots proxy

This commit is contained in:
Evan You 2024-12-06 22:45:45 +08:00
parent 685f7820a1
commit 3ef1656d4a
No known key found for this signature in database
GPG Key ID: 00E9AB7A6704CE0A
2 changed files with 78 additions and 6 deletions

View File

@ -34,8 +34,8 @@ import { setStyle } from './dom/style'
import { setClass, setDynamicProp } from './dom/prop'
import {
type RawSlots,
type Slot,
getSlotsProxyHandlers,
type StaticSlots,
slotsProxyHandlers,
} from './componentSlots'
export { currentInstance } from '@vue/runtime-dom'
@ -178,7 +178,7 @@ export class VaporComponentInstance implements GenericComponentInstance {
rawProps: RawProps
props: Record<string, any>
attrs: Record<string, any>
slots: Record<string, Slot>
slots: StaticSlots
exposed: Record<string, any> | null
emitted: Record<string, boolean> | null
@ -257,9 +257,7 @@ export class VaporComponentInstance implements GenericComponentInstance {
}
// init slots
this.slots = rawSlots
? new Proxy(rawSlots, getSlotsProxyHandlers(comp))
: EMPTY_OBJ
this.slots = rawSlots ? new Proxy(rawSlots, slotsProxyHandlers) : EMPTY_OBJ
if (__DEV__) {
// validate props

View File

@ -0,0 +1,74 @@
import { NO, hasOwn, isArray, isFunction } from '@vue/shared'
import type { Block } from './block'
export type RawSlots = Record<string, Slot> & {
$?: (StaticSlots | DynamicSlotFn)[]
}
export type StaticSlots = Record<string, Slot>
export type Slot = (...args: any[]) => Block
export type DynamicSlot = { name: string; fn: Slot }
export type DynamicSlotFn = () => DynamicSlot | DynamicSlot[]
export const slotsProxyHandlers: ProxyHandler<RawSlots> = {
get: getSlot,
has: (target, key: string) => !!getSlot(target, key),
getOwnPropertyDescriptor(target, key: string) {
const slot = getSlot(target, key)
if (slot) {
return {
configurable: true,
enumerable: true,
value: slot,
}
}
},
ownKeys(target) {
const keys = Object.keys(target)
const dynamicSources = target.$
if (dynamicSources) {
for (const source of dynamicSources) {
if (isFunction(source)) {
const slot = source()
if (isArray(slot)) {
for (const s of slot) keys.push(s.name)
} else {
keys.push(slot.name)
}
} else {
keys.push(...Object.keys(source))
}
}
}
return keys
},
set: NO,
deleteProperty: NO,
}
function getSlot(target: RawSlots, key: string) {
const dynamicSources = target.$
if (dynamicSources) {
let i = dynamicSources.length
let source
while (i--) {
source = dynamicSources[i]
if (isFunction(source)) {
const slot = source()
if (isArray(slot)) {
for (const s of slot) {
if (s.name === key) return s.fn
}
} else if (slot.name === key) {
return slot.fn
}
} else if (hasOwn(source, key)) {
return source[key]
}
}
}
if (hasOwn(target, key)) {
return target[key]
}
}