From: Evan You Date: Fri, 11 Nov 2022 06:42:42 +0000 (+0800) Subject: fix(custom-elements): properties set pre-upgrade should not show up in $attrs X-Git-Tag: v3.2.45~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=afe889999cbcaa11020c46c30b591a5ee6c3d4cf;p=thirdparty%2Fvuejs%2Fcore.git fix(custom-elements): properties set pre-upgrade should not show up in $attrs --- diff --git a/packages/runtime-dom/__tests__/customElement.spec.ts b/packages/runtime-dom/__tests__/customElement.spec.ts index 03a5361d69..09ee971d22 100644 --- a/packages/runtime-dom/__tests__/customElement.spec.ts +++ b/packages/runtime-dom/__tests__/customElement.spec.ts @@ -230,6 +230,33 @@ describe('defineCustomElement', () => { }) }) + describe('attrs', () => { + const E = defineCustomElement({ + render() { + return [h('div', null, this.$attrs.foo as string)] + } + }) + customElements.define('my-el-attrs', E) + + test('attrs via attribute', async () => { + container.innerHTML = `` + const e = container.childNodes[0] as VueElement + expect(e.shadowRoot!.innerHTML).toBe('
hello
') + + e.setAttribute('foo', 'changed') + await nextTick() + expect(e.shadowRoot!.innerHTML).toBe('
changed
') + }) + + test('non-declared properties should not show up in $attrs', () => { + const e = new E() + // @ts-ignore + e.foo = '123' + container.appendChild(e) + expect(e.shadowRoot!.innerHTML).toBe('
') + }) + }) + describe('emits', () => { const CompDef = defineComponent({ setup(_, { emit }) { diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts index 55530b98c3..ebb1eccc0b 100644 --- a/packages/runtime-dom/src/apiCustomElement.ts +++ b/packages/runtime-dom/src/apiCustomElement.ts @@ -228,13 +228,12 @@ export class VueElement extends BaseClass { }).observe(this, { attributes: true }) const resolve = (def: InnerComponentDef) => { - const { props = {}, styles } = def - const hasOptions = !isArray(props) - const rawKeys = props ? (hasOptions ? Object.keys(props) : props) : [] + const { props, styles } = def + const declaredPropKeys = isArray(props) ? props : Object.keys(props || {}) // cast Number-type props set before resolve let numberProps - if (hasOptions) { + if (props && !isArray(props)) { for (const key in this._props) { const opt = props[key] if (opt === Number || (opt && opt.type === Number)) { @@ -247,18 +246,13 @@ export class VueElement extends BaseClass { // check if there are props set pre-upgrade or connect for (const key of Object.keys(this)) { - if (key[0] !== '_') { - this._setProp( - key, - this[key as keyof this], - rawKeys.includes(key), - false - ) + if (key[0] !== '_' && declaredPropKeys.includes(key)) { + this._setProp(key, this[key as keyof this], true, false) } } // defining getter/setters on prototype - for (const key of rawKeys.map(camelize)) { + for (const key of declaredPropKeys.map(camelize)) { Object.defineProperty(this, key, { get() { return this._getProp(key)