diff --git a/packages/runtime-dom/__tests__/customElement.spec.ts b/packages/runtime-dom/__tests__/customElement.spec.ts
index 9db0de9cf74..8b3b440f24f 100644
--- a/packages/runtime-dom/__tests__/customElement.spec.ts
+++ b/packages/runtime-dom/__tests__/customElement.spec.ts
@@ -223,6 +223,31 @@ describe('defineCustomElement', () => {
expect(e.getAttribute('baz-qux')).toBe('four')
})
+ test('props via attributes and properties changed together', async () => {
+ const e = new E()
+ e.foo = 'foo1'
+ e.bar = { x: 'bar1' }
+ container.appendChild(e)
+ await nextTick()
+ expect(e.shadowRoot!.innerHTML).toBe('
foo1
bar1
')
+
+ // change attr then property
+ e.setAttribute('foo', 'foo2')
+ e.bar = { x: 'bar2' }
+ await nextTick()
+ expect(e.shadowRoot!.innerHTML).toBe('foo2
bar2
')
+ expect(e.getAttribute('foo')).toBe('foo2')
+ expect(e.hasAttribute('bar')).toBe(false)
+
+ // change prop then attr
+ e.bar = { x: 'bar3' }
+ e.setAttribute('foo', 'foo3')
+ await nextTick()
+ expect(e.shadowRoot!.innerHTML).toBe('foo3
bar3
')
+ expect(e.getAttribute('foo')).toBe('foo3')
+ expect(e.hasAttribute('bar')).toBe(false)
+ })
+
test('props via hyphen property', async () => {
const Comp = defineCustomElement({
props: {
diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts
index d99a9341bd9..6d6dccc6e90 100644
--- a/packages/runtime-dom/src/apiCustomElement.ts
+++ b/packages/runtime-dom/src/apiCustomElement.ts
@@ -346,6 +346,12 @@ export class VueElement
})
}
+ private _processMutations(mutations: MutationRecord[]) {
+ for (const m of mutations) {
+ this._setAttr(m.attributeName!)
+ }
+ }
+
/**
* resolve inner component definition (handle possible async component)
*/
@@ -360,11 +366,7 @@ export class VueElement
}
// watch future attr changes
- this._ob = new MutationObserver(mutations => {
- for (const m of mutations) {
- this._setAttr(m.attributeName!)
- }
- })
+ this._ob = new MutationObserver(this._processMutations.bind(this))
this._ob.observe(this, { attributes: true })
@@ -514,7 +516,10 @@ export class VueElement
// reflect
if (shouldReflect) {
const ob = this._ob
- ob && ob.disconnect()
+ if (ob) {
+ this._processMutations(ob.takeRecords())
+ ob.disconnect()
+ }
if (val === true) {
this.setAttribute(hyphenate(key), '')
} else if (typeof val === 'string' || typeof val === 'number') {