From: linzhe <40790268+linzhe141@users.noreply.github.com> Date: Wed, 23 Jul 2025 00:40:40 +0000 (+0800) Subject: fix(custom-element): ensure exposed methods are accessible from custom elements by... X-Git-Tag: v3.5.18~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=90573b06bf6fb6c14c6bbff6c4e34e0ab108953a;p=thirdparty%2Fvuejs%2Fcore.git fix(custom-element): ensure exposed methods are accessible from custom elements by making them enumerable (#13634) close #13632 --- diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 5db6a0a176..25d21477cf 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -756,6 +756,7 @@ export function applyOptions(instance: ComponentInternalInstance): void { Object.defineProperty(exposed, key, { get: () => publicThis[key], set: val => (publicThis[key] = val), + enumerable: true, }) }) } else if (!instance.exposed) { diff --git a/packages/runtime-dom/__tests__/customElement.spec.ts b/packages/runtime-dom/__tests__/customElement.spec.ts index c44840df5e..07ea091486 100644 --- a/packages/runtime-dom/__tests__/customElement.spec.ts +++ b/packages/runtime-dom/__tests__/customElement.spec.ts @@ -1402,6 +1402,34 @@ describe('defineCustomElement', () => { }) describe('expose', () => { + test('expose w/ options api', async () => { + const E = defineCustomElement({ + data() { + return { + value: 0, + } + }, + methods: { + foo() { + ;(this as any).value++ + }, + }, + expose: ['foo'], + render(_ctx: any) { + return h('div', null, _ctx.value) + }, + }) + customElements.define('my-el-expose-options-api', E) + + container.innerHTML = `` + const e = container.childNodes[0] as VueElement & { + foo: () => void + } + expect(e.shadowRoot!.innerHTML).toBe(`
0
`) + e.foo() + await nextTick() + expect(e.shadowRoot!.innerHTML).toBe(`
1
`) + }) test('expose attributes and callback', async () => { type SetValue = (value: string) => void let fn: MockedFunction