@@ -8,12 +8,16 @@ import {
88 isFunction ,
99 extend
1010} from '@vue/shared'
11- import { ComponentInternalInstance , ConcreteComponent } from './component'
11+ import {
12+ ComponentInternalInstance ,
13+ ComponentOptions ,
14+ ConcreteComponent
15+ } from './component'
1216import { callWithAsyncErrorHandling , ErrorCodes } from './errorHandling'
1317import { warn } from './warning'
14- import { normalizePropsOptions } from './componentProps'
1518import { UnionToIntersection } from './helpers/typeUtils'
1619import { devtoolsComponentEmit } from './devtools'
20+ import { AppContext } from './apiCreateApp'
1721
1822export type ObjectEmitsOptions = Record <
1923 string ,
@@ -44,18 +48,20 @@ export function emit(
4448 const props = instance . vnode . props || EMPTY_OBJ
4549
4650 if ( __DEV__ ) {
47- const options = normalizeEmitsOptions ( instance . type )
48- if ( options ) {
49- if ( ! ( event in options ) ) {
50- const propsOptions = normalizePropsOptions ( instance . type ) [ 0 ]
51+ const {
52+ emitsOptions,
53+ propsOptions : [ propsOptions ]
54+ } = instance
55+ if ( emitsOptions ) {
56+ if ( ! ( event in emitsOptions ) ) {
5157 if ( ! propsOptions || ! ( `on` + capitalize ( event ) in propsOptions ) ) {
5258 warn (
5359 `Component emitted event "${ event } " but it is neither declared in ` +
5460 `the emits option nor as an "on${ capitalize ( event ) } " prop.`
5561 )
5662 }
5763 } else {
58- const validator = options [ event ]
64+ const validator = emitsOptions [ event ]
5965 if ( isFunction ( validator ) ) {
6066 const isValid = validator ( ...args )
6167 if ( ! isValid ) {
@@ -98,11 +104,16 @@ export function emit(
98104 }
99105}
100106
101- function normalizeEmitsOptions (
102- comp : ConcreteComponent
103- ) : ObjectEmitsOptions | undefined {
104- if ( hasOwn ( comp , '__emits' ) ) {
105- return comp . __emits
107+ export function normalizeEmitsOptions (
108+ comp : ConcreteComponent ,
109+ appContext : AppContext ,
110+ asMixin = false
111+ ) : ObjectEmitsOptions | null {
112+ const appId = appContext . app ? appContext . app . _uid : - 1
113+ const cache = comp . __emits || ( comp . __emits = { } )
114+ const cached = cache [ appId ]
115+ if ( cached !== undefined ) {
116+ return cached
106117 }
107118
108119 const raw = comp . emits
@@ -111,39 +122,46 @@ function normalizeEmitsOptions(
111122 // apply mixin/extends props
112123 let hasExtends = false
113124 if ( __FEATURE_OPTIONS_API__ && ! isFunction ( comp ) ) {
114- if ( comp . extends ) {
125+ const extendEmits = ( raw : ComponentOptions ) => {
115126 hasExtends = true
116- extend ( normalized , normalizeEmitsOptions ( comp . extends ) )
127+ extend ( normalized , normalizeEmitsOptions ( raw , appContext , true ) )
128+ }
129+ if ( ! asMixin && appContext . mixins . length ) {
130+ appContext . mixins . forEach ( extendEmits )
131+ }
132+ if ( comp . extends ) {
133+ extendEmits ( comp . extends )
117134 }
118135 if ( comp . mixins ) {
119- hasExtends = true
120- comp . mixins . forEach ( m => extend ( normalized , normalizeEmitsOptions ( m ) ) )
136+ comp . mixins . forEach ( extendEmits )
121137 }
122138 }
123139
124140 if ( ! raw && ! hasExtends ) {
125- return ( comp . __emits = undefined )
141+ return ( cache [ appId ] = null )
126142 }
127143
128144 if ( isArray ( raw ) ) {
129145 raw . forEach ( key => ( normalized [ key ] = null ) )
130146 } else {
131147 extend ( normalized , raw )
132148 }
133- return ( comp . __emits = normalized )
149+ return ( cache [ appId ] = normalized )
134150}
135151
136152// Check if an incoming prop key is a declared emit event listener.
137153// e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are
138154// both considered matched listeners.
139- export function isEmitListener ( comp : ConcreteComponent , key : string ) : boolean {
140- let emits : ObjectEmitsOptions | undefined
141- if ( ! isOn ( key ) || ! ( emits = normalizeEmitsOptions ( comp ) ) ) {
155+ export function isEmitListener (
156+ options : ObjectEmitsOptions | null ,
157+ key : string
158+ ) : boolean {
159+ if ( ! options || ! isOn ( key ) ) {
142160 return false
143161 }
144162 key = key . replace ( / O n c e $ / , '' )
145163 return (
146- hasOwn ( emits , key [ 2 ] . toLowerCase ( ) + key . slice ( 3 ) ) ||
147- hasOwn ( emits , key . slice ( 2 ) )
164+ hasOwn ( options , key [ 2 ] . toLowerCase ( ) + key . slice ( 3 ) ) ||
165+ hasOwn ( options , key . slice ( 2 ) )
148166 )
149167}
0 commit comments