refactor(runtime-core): extract component emit related logic into dedicated file
This commit is contained in:
93
packages/runtime-core/src/componentEmits.ts
Normal file
93
packages/runtime-core/src/componentEmits.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import {
|
||||
isArray,
|
||||
isOn,
|
||||
hasOwn,
|
||||
EMPTY_OBJ,
|
||||
capitalize,
|
||||
hyphenate
|
||||
} from '@vue/shared'
|
||||
import { ComponentInternalInstance } from './component'
|
||||
import { callWithAsyncErrorHandling, ErrorCodes } from './errorHandling'
|
||||
|
||||
export type ObjectEmitsOptions = Record<
|
||||
string,
|
||||
((...args: any[]) => any) | null
|
||||
>
|
||||
export type EmitsOptions = ObjectEmitsOptions | string[]
|
||||
|
||||
type UnionToIntersection<U> = (U extends any
|
||||
? (k: U) => void
|
||||
: never) extends ((k: infer I) => void)
|
||||
? I
|
||||
: never
|
||||
|
||||
export type EmitFn<
|
||||
Options = ObjectEmitsOptions,
|
||||
Event extends keyof Options = keyof Options
|
||||
> = Options extends any[]
|
||||
? (event: Options[0], ...args: any[]) => unknown[]
|
||||
: UnionToIntersection<
|
||||
{
|
||||
[key in Event]: Options[key] extends ((...args: infer Args) => any)
|
||||
? (event: key, ...args: Args) => unknown[]
|
||||
: (event: key, ...args: any[]) => unknown[]
|
||||
}[Event]
|
||||
>
|
||||
|
||||
export function emit(
|
||||
instance: ComponentInternalInstance,
|
||||
event: string,
|
||||
...args: any[]
|
||||
): any[] {
|
||||
const props = instance.vnode.props || EMPTY_OBJ
|
||||
let handler = props[`on${event}`] || props[`on${capitalize(event)}`]
|
||||
// for v-model update:xxx events, also trigger kebab-case equivalent
|
||||
// for props passed via kebab-case
|
||||
if (!handler && event.indexOf('update:') === 0) {
|
||||
event = hyphenate(event)
|
||||
handler = props[`on${event}`] || props[`on${capitalize(event)}`]
|
||||
}
|
||||
if (handler) {
|
||||
const res = callWithAsyncErrorHandling(
|
||||
handler,
|
||||
instance,
|
||||
ErrorCodes.COMPONENT_EVENT_HANDLER,
|
||||
args
|
||||
)
|
||||
return isArray(res) ? res : [res]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeEmitsOptions(
|
||||
options: EmitsOptions | undefined
|
||||
): ObjectEmitsOptions | undefined {
|
||||
if (!options) {
|
||||
return
|
||||
} else if (isArray(options)) {
|
||||
if ((options as any)._n) {
|
||||
return (options as any)._n
|
||||
}
|
||||
const normalized: ObjectEmitsOptions = {}
|
||||
options.forEach(key => (normalized[key] = null))
|
||||
Object.defineProperty(options, '_n', { value: normalized })
|
||||
return normalized
|
||||
} else {
|
||||
return options
|
||||
}
|
||||
}
|
||||
|
||||
// Check if an incoming prop key is a declared emit event listener.
|
||||
// e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are
|
||||
// both considered matched listeners.
|
||||
export function isEmitListener(
|
||||
emits: ObjectEmitsOptions,
|
||||
key: string
|
||||
): boolean {
|
||||
return (
|
||||
isOn(key) &&
|
||||
(hasOwn(emits, key[2].toLowerCase() + key.slice(3)) ||
|
||||
hasOwn(emits, key.slice(2)))
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user