vue3-core/packages/runtime-vapor/src/apiTemplateRef.ts

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

150 lines
4.0 KiB
TypeScript
Raw Normal View History

import { type Ref, isRef, onScopeDispose } from '@vue/reactivity'
import {
2024-12-04 14:22:26 +08:00
type VaporComponentInstance,
currentInstance,
2024-12-11 11:50:17 +08:00
getExposed,
isVaporComponent,
2024-12-12 22:34:35 +08:00
} from './component'
2024-12-04 14:22:26 +08:00
import {
2025-01-30 10:12:36 +08:00
ErrorCodes,
2024-12-04 14:22:26 +08:00
type SchedulerJob,
callWithErrorHandling,
queuePostFlushCb,
warn,
} from '@vue/runtime-dom'
import {
EMPTY_OBJ,
hasOwn,
isArray,
isFunction,
isString,
remove,
} from '@vue/shared'
2025-05-13 17:19:48 +08:00
import { isFragment } from './block'
2024-01-20 23:48:10 +08:00
export type NodeRef = string | Ref | ((ref: Element) => void)
2024-12-04 14:22:26 +08:00
export type RefEl = Element | VaporComponentInstance
2024-01-20 23:48:10 +08:00
2024-12-12 22:34:35 +08:00
export type setRefFn = (
el: RefEl,
ref: NodeRef,
oldRef?: NodeRef,
refFor?: boolean,
) => NodeRef | undefined
export function createTemplateRefSetter(): setRefFn {
const instance = currentInstance as VaporComponentInstance
return (...args) => setRef(instance, ...args)
}
2024-01-20 23:48:10 +08:00
/**
* Function for handling a template ref
*/
export function setRef(
2024-12-12 22:34:35 +08:00
instance: VaporComponentInstance,
el: RefEl,
ref: NodeRef,
oldRef?: NodeRef,
refFor = false,
): NodeRef | undefined {
2024-12-12 22:34:35 +08:00
if (!instance || instance.isUnmounted) return
2025-05-13 17:19:48 +08:00
if (isFragment(el) && el.setRef) {
el.setRef(instance, ref, refFor)
return
}
2024-12-12 22:34:35 +08:00
const setupState: any = __DEV__ ? instance.setupState || {} : null
2024-12-11 11:50:17 +08:00
const refValue = isVaporComponent(el) ? getExposed(el) || el : el
2024-01-21 13:59:56 +08:00
const refs =
2024-12-12 22:34:35 +08:00
instance.refs === EMPTY_OBJ ? (instance.refs = {}) : instance.refs
2024-01-21 13:59:56 +08:00
// dynamic ref changed. unset old ref
if (oldRef != null && oldRef !== ref) {
if (isString(oldRef)) {
refs[oldRef] = null
2024-12-12 22:34:35 +08:00
if (__DEV__ && hasOwn(setupState, oldRef)) {
setupState[oldRef] = null
}
} else if (isRef(oldRef)) {
oldRef.value = null
}
}
2024-01-20 23:48:10 +08:00
if (isFunction(ref)) {
const invokeRefSetter = (value?: Element | Record<string, any>) => {
2025-01-30 10:12:36 +08:00
callWithErrorHandling(ref, currentInstance, ErrorCodes.FUNCTION_REF, [
value,
refs,
])
}
invokeRefSetter(refValue)
2024-12-12 22:34:35 +08:00
// TODO this gets called repeatedly in renderEffect when it's dynamic ref?
onScopeDispose(() => invokeRefSetter())
2024-01-20 23:48:10 +08:00
} else {
const _isString = isString(ref)
const _isRef = isRef(ref)
let existing: unknown
2024-01-20 23:48:10 +08:00
if (_isString || _isRef) {
const doSet: SchedulerJob = () => {
if (refFor) {
existing = _isString
2024-12-12 22:34:35 +08:00
? __DEV__ && hasOwn(setupState, ref)
? setupState[ref]
: refs[ref]
: ref.value
if (!isArray(existing)) {
existing = [refValue]
if (_isString) {
refs[ref] = existing
2024-12-12 22:34:35 +08:00
if (__DEV__ && hasOwn(setupState, ref)) {
setupState[ref] = refs[ref]
// if setupState[ref] is a reactivity ref,
// the existing will also become reactivity too
// need to get the Proxy object by resetting
existing = setupState[ref]
}
} else {
ref.value = existing
}
} else if (!existing.includes(refValue)) {
existing.push(refValue)
}
} else if (_isString) {
refs[ref] = refValue
2024-12-12 22:34:35 +08:00
if (__DEV__ && hasOwn(setupState, ref)) {
setupState[ref] = refValue
2024-01-20 23:48:10 +08:00
}
} else if (_isRef) {
ref.value = refValue
2024-01-20 23:48:10 +08:00
} else if (__DEV__) {
warn('Invalid template ref type:', ref, `(${typeof ref})`)
}
}
doSet.id = -1
queuePostFlushCb(doSet)
2024-12-12 22:34:35 +08:00
// TODO this gets called repeatedly in renderEffect when it's dynamic ref?
onScopeDispose(() => {
queuePostFlushCb(() => {
if (isArray(existing)) {
remove(existing, refValue)
} else if (_isString) {
refs[ref] = null
2024-12-12 22:34:35 +08:00
if (__DEV__ && hasOwn(setupState, ref)) {
setupState[ref] = null
}
} else if (_isRef) {
ref.value = null
}
})
})
2024-01-20 23:48:10 +08:00
} else if (__DEV__) {
2024-12-12 22:34:35 +08:00
warn('Invalid template ref type:', ref, `(${typeof ref})`)
2024-01-20 23:48:10 +08:00
}
}
return ref
2024-01-20 23:48:10 +08:00
}