From: Evan You Date: Thu, 8 Aug 2024 10:37:54 +0000 (+0800) Subject: fix(custom-element): delete prop on attribute removal X-Git-Tag: v3.5.0-beta.1~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=506c4c53fdf9766c2ce9517ad58d501ef6b1b9de;p=thirdparty%2Fvuejs%2Fcore.git fix(custom-element): delete prop on attribute removal close #11276 --- diff --git a/packages/runtime-dom/__tests__/customElement.spec.ts b/packages/runtime-dom/__tests__/customElement.spec.ts index da0d614f65..ac66230e32 100644 --- a/packages/runtime-dom/__tests__/customElement.spec.ts +++ b/packages/runtime-dom/__tests__/customElement.spec.ts @@ -1241,4 +1241,25 @@ describe('defineCustomElement', () => { expect(e.shadowRoot!.innerHTML).toBe(`
fooValue
`) app.unmount() }) + + // #11276 + test('delete prop on attr removal', async () => { + const E = defineCustomElement({ + props: { + boo: { + type: Boolean, + }, + }, + render() { + return this.boo + ',' + typeof this.boo + }, + }) + customElements.define('el-attr-removal', E) + container.innerHTML = '' + const e = container.childNodes[0] as VueElement + expect(e.shadowRoot!.innerHTML).toBe(`true,boolean`) + e.removeAttribute('boo') + await nextTick() + expect(e.shadowRoot!.innerHTML).toBe(`false,boolean`) + }) }) diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts index aa191ba6c7..fe0e4d90b7 100644 --- a/packages/runtime-dom/src/apiCustomElement.ts +++ b/packages/runtime-dom/src/apiCustomElement.ts @@ -42,6 +42,9 @@ import { } from '@vue/shared' import { createApp, createSSRApp, render } from '.' +// marker for attr removal +const REMOVAL = {} + export type VueElementConstructor

= { new (initialProps?: Record): VueElement & P } @@ -455,9 +458,10 @@ export class VueElement protected _setAttr(key: string) { if (key.startsWith('data-v-')) return - let value = this.hasAttribute(key) ? this.getAttribute(key) : undefined + const has = this.hasAttribute(key) + let value = has ? this.getAttribute(key) : REMOVAL const camelKey = camelize(key) - if (this._numberProps && this._numberProps[camelKey]) { + if (has && this._numberProps && this._numberProps[camelKey]) { value = toNumber(value) } this._setProp(camelKey, value, false, true) @@ -475,7 +479,11 @@ export class VueElement */ _setProp(key: string, val: any, shouldReflect = true, shouldUpdate = false) { if (val !== this._props[key]) { - this._props[key] = val + if (val === REMOVAL) { + delete this._props[key] + } else { + this._props[key] = val + } if (shouldUpdate && this._instance) { this._update() }