Skip to content

Commit 2b82824

Browse files
committed
fix(custom-element): set prop runs pending mutations before disconnect
1 parent b555f02 commit 2b82824

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed

packages/runtime-dom/__tests__/customElement.spec.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,31 @@ describe('defineCustomElement', () => {
223223
expect(e.getAttribute('baz-qux')).toBe('four')
224224
})
225225

226+
test('props via attributes and properties changed together', async () => {
227+
const e = new E()
228+
e.foo = 'foo1'
229+
e.bar = { x: 'bar1' }
230+
container.appendChild(e)
231+
await nextTick()
232+
expect(e.shadowRoot!.innerHTML).toBe('<div>foo1</div><div>bar1</div>')
233+
234+
// change attr then property
235+
e.setAttribute('foo', 'foo2')
236+
e.bar = { x: 'bar2' }
237+
await nextTick()
238+
expect(e.shadowRoot!.innerHTML).toBe('<div>foo2</div><div>bar2</div>')
239+
expect(e.getAttribute('foo')).toBe('foo2')
240+
expect(e.hasAttribute('bar')).toBe(false)
241+
242+
// change prop then attr
243+
e.bar = { x: 'bar3' }
244+
e.setAttribute('foo', 'foo3')
245+
await nextTick()
246+
expect(e.shadowRoot!.innerHTML).toBe('<div>foo3</div><div>bar3</div>')
247+
expect(e.getAttribute('foo')).toBe('foo3')
248+
expect(e.hasAttribute('bar')).toBe(false)
249+
})
250+
226251
test('props via hyphen property', async () => {
227252
const Comp = defineCustomElement({
228253
props: {

packages/runtime-dom/src/apiCustomElement.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,12 @@ export class VueElement
342342
})
343343
}
344344

345+
private _processMutations(mutations: MutationRecord[]) {
346+
for (const m of mutations) {
347+
this._setAttr(m.attributeName!)
348+
}
349+
}
350+
345351
/**
346352
* resolve inner component definition (handle possible async component)
347353
*/
@@ -356,11 +362,7 @@ export class VueElement
356362
}
357363

358364
// watch future attr changes
359-
this._ob = new MutationObserver(mutations => {
360-
for (const m of mutations) {
361-
this._setAttr(m.attributeName!)
362-
}
363-
})
365+
this._ob = new MutationObserver(this._processMutations.bind(this))
364366

365367
this._ob.observe(this, { attributes: true })
366368

@@ -510,7 +512,10 @@ export class VueElement
510512
// reflect
511513
if (shouldReflect) {
512514
const ob = this._ob
513-
ob && ob.disconnect()
515+
if (ob) {
516+
this._processMutations(ob.takeRecords())
517+
ob.disconnect()
518+
}
514519
if (val === true) {
515520
this.setAttribute(hyphenate(key), '')
516521
} else if (typeof val === 'string' || typeof val === 'number') {

0 commit comments

Comments
 (0)