mirror of https://github.com/vuejs/core.git
fix(custom-element): disconnect MutationObserver in nextTick in case that custom elements are moved (#10613)
Closes #10610
This commit is contained in:
parent
392bd9baa1
commit
bbb5be299b
|
@ -1,6 +1,7 @@
|
||||||
import {
|
import {
|
||||||
type Ref,
|
type Ref,
|
||||||
type VueElement,
|
type VueElement,
|
||||||
|
createApp,
|
||||||
defineAsyncComponent,
|
defineAsyncComponent,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
defineCustomElement,
|
defineCustomElement,
|
||||||
|
@ -60,6 +61,54 @@ describe('defineCustomElement', () => {
|
||||||
expect(e.shadowRoot!.innerHTML).toBe('')
|
expect(e.shadowRoot!.innerHTML).toBe('')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #10610
|
||||||
|
test('When elements move, avoid prematurely disconnecting MutationObserver', async () => {
|
||||||
|
const CustomInput = defineCustomElement({
|
||||||
|
props: ['value'],
|
||||||
|
emits: ['update'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
return () =>
|
||||||
|
h('input', {
|
||||||
|
type: 'number',
|
||||||
|
value: props.value,
|
||||||
|
onInput: (e: InputEvent) => {
|
||||||
|
const num = (e.target! as HTMLInputElement).valueAsNumber
|
||||||
|
emit('update', Number.isNaN(num) ? null : num)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
customElements.define('my-el-input', CustomInput)
|
||||||
|
const num = ref('12')
|
||||||
|
const containerComp = defineComponent({
|
||||||
|
setup() {
|
||||||
|
return () => {
|
||||||
|
return h('div', [
|
||||||
|
h('my-el-input', {
|
||||||
|
value: num.value,
|
||||||
|
onUpdate: ($event: CustomEvent) => {
|
||||||
|
num.value = $event.detail[0]
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
h('div', { id: 'move' }),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const app = createApp(containerComp)
|
||||||
|
app.mount(container)
|
||||||
|
const myInputEl = container.querySelector('my-el-input')!
|
||||||
|
const inputEl = myInputEl.shadowRoot!.querySelector('input')!
|
||||||
|
await nextTick()
|
||||||
|
expect(inputEl.value).toBe('12')
|
||||||
|
const moveEl = container.querySelector('#move')!
|
||||||
|
moveEl.append(myInputEl)
|
||||||
|
await nextTick()
|
||||||
|
myInputEl.removeAttribute('value')
|
||||||
|
await nextTick()
|
||||||
|
expect(inputEl.value).toBe('')
|
||||||
|
})
|
||||||
|
|
||||||
test('should not unmount on move', async () => {
|
test('should not unmount on move', async () => {
|
||||||
container.innerHTML = `<div><my-element></my-element></div>`
|
container.innerHTML = `<div><my-element></my-element></div>`
|
||||||
const e = container.childNodes[0].childNodes[0] as VueElement
|
const e = container.childNodes[0].childNodes[0] as VueElement
|
||||||
|
|
|
@ -215,12 +215,12 @@ export class VueElement extends BaseClass {
|
||||||
|
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
this._connected = false
|
this._connected = false
|
||||||
if (this._ob) {
|
|
||||||
this._ob.disconnect()
|
|
||||||
this._ob = null
|
|
||||||
}
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
if (!this._connected) {
|
if (!this._connected) {
|
||||||
|
if (this._ob) {
|
||||||
|
this._ob.disconnect()
|
||||||
|
this._ob = null
|
||||||
|
}
|
||||||
render(null, this.shadowRoot!)
|
render(null, this.shadowRoot!)
|
||||||
this._instance = null
|
this._instance = null
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue