From: Evan You Date: Sat, 3 Aug 2024 05:46:58 +0000 (+0800) Subject: feat(custom-element): support emit with options X-Git-Tag: v3.5.0-beta.1~36 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e181bff6dc39d5cef92000c10291243c7d6e4d08;p=thirdparty%2Fvuejs%2Fcore.git feat(custom-element): support emit with options In a custom element created via `defineCustomElement`, if the first event argument is an object, it will be used as the options object for the emitted CustomEvent. The entire argument list is still exposed via the CustomEvent's `detail` property. ```js emit('event', { bubbles: true }) ``` close #7605 --- diff --git a/packages/runtime-dom/__tests__/customElement.spec.ts b/packages/runtime-dom/__tests__/customElement.spec.ts index ab4d6f4793..1ed7cc2531 100644 --- a/packages/runtime-dom/__tests__/customElement.spec.ts +++ b/packages/runtime-dom/__tests__/customElement.spec.ts @@ -408,6 +408,9 @@ describe('defineCustomElement', () => { onMousedown: () => { emit('myEvent', 1) // validate hyphenation }, + onWheel: () => { + emit('my-wheel', { bubbles: true }, 1) + }, }) }, }) @@ -467,6 +470,7 @@ describe('defineCustomElement', () => { detail: [1], }) }) + // #7293 test('emit in an async component wrapper with properties bound', async () => { const E = defineCustomElement( @@ -488,6 +492,19 @@ describe('defineCustomElement', () => { detail: [1], }) }) + + test('emit with options', async () => { + container.innerHTML = `` + const e = container.childNodes[0] as VueElement + const spy = vi.fn() + e.addEventListener('my-wheel', spy) + e.shadowRoot!.childNodes[0].dispatchEvent(new CustomEvent('wheel')) + expect(spy).toHaveBeenCalledTimes(1) + expect(spy.mock.calls[0][0]).toMatchObject({ + bubbles: true, + detail: [{ bubbles: true }, 1], + }) + }) }) describe('slots', () => { diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts index 5c421b38ed..4767237079 100644 --- a/packages/runtime-dom/src/apiCustomElement.ts +++ b/packages/runtime-dom/src/apiCustomElement.ts @@ -27,7 +27,14 @@ import { nextTick, warn, } from '@vue/runtime-core' -import { camelize, extend, hyphenate, isArray, toNumber } from '@vue/shared' +import { + camelize, + extend, + hyphenate, + isArray, + isPlainObject, + toNumber, +} from '@vue/shared' import { hydrate, render } from '.' export type VueElementConstructor

= { @@ -405,9 +412,12 @@ export class VueElement extends BaseClass { const dispatch = (event: string, args: any[]) => { this.dispatchEvent( - new CustomEvent(event, { - detail: args, - }), + new CustomEvent( + event, + isPlainObject(args[0]) + ? extend({ detail: args }, args[0]) + : { detail: args }, + ), ) }