element
element copied to clipboard
[Bug Report] destroy-on-close in el-dialog will invoke inner component's created method
Element UI version
2.13.0
OS/Browsers version
chrome
Vue version
2.6.11
Reproduction Link
https://codepen.io/duan1993/pen/eYNMdxZ
Steps to reproduce
- click "点击打开 Dialog" button, will alert(1)
- click "X" button, will alert(1) again
What is Expected?
when click "X" button, will not alert(1)
What is actually happening?
when click "X" button, will alert(1)
Translation of this issue:
Element UI version
2.13.0
OS/Browsers version
Chrome
Vue version
2.6.11
Reproduction Link
https://codepen.io/duan1993/pen/eYNMdxZ
Steps to reproduce
-
Click "click to open dialog" button, will alert (1)
-
click "X" button, will alert(1) again
What is Expected?
when click "X" button, will not alert(1)
What is actually happening?
when click "X" button, will alert(1)
This is because the el-dialog component uses a key attribute on a inner div which wraps the slot of your component. When you close a el-dialog with 'destroy-on-close' attribute set, the el-dialog just executes a 'key++' which causes your component rebuilding but not destory your component as we expect. Here is part of the source code of el-dialog and I cannot see why they are doing this:
if (this.destroyOnClose) {
this.$nextTick(() => {
this.key++;
});
}
Any guesses how to destroy el-dialog properly (without 'mount' execute immediately after closing)?
destory-on-close
will cause high CPU and the page become unresponsive ...
This does the work for me:
I went inside the package and modify a few places, thank to @veah for pointing that out
i add visibleWithDestroy
and a v-if
condition like so:
data() {
return {
closed: false,
// key: 0,
visibleWithDestroy: true,
}
},
...
<div
v-show="visible"
class="el-dialog__wrapper"
@click.self="handleWrapperClick"
>
<div
v-if="visibleWithDestroy"
ref="dialog"
role="dialog"
aria-modal="true"
:aria-label="title || 'dialog'"
:class="[
'el-dialog',
{ 'is-fullscreen': fullscreen, 'el-dialog--center': center },
customClass,
]"
:style="style"
>
...
In the visible wacther i stopped using the original key
method for destroying the inner dialog and use the new visibleWithDestroy
instead
watch: {
visible(val) {
if (val) {
this.visibleWithDestroy = true
this.closed = false
this.$emit('open')
this.$el.addEventListener('scroll', this.updatePopper)
this.$nextTick(() => {
this.$refs.dialog.scrollTop = 0
})
if (this.appendToBody) {
document.body.appendChild(this.$el)
}
} else {
this.$el.removeEventListener('scroll', this.updatePopper)
if (!this.closed) this.$emit('close')
if (this.destroyOnClose) {
this.$nextTick(() => {
// this.key++
this.visibleWithDestroy = false
})
}
}
},
},
same +1
if inner component has API call when it is created, that is too bad.
this Fix should be merged
To anyone bumping into this weird bug in 2022 - A quick n easy DIY destroy-on-close : Just use v-if on the template your sending inside the el-dialog with the same property used to open it :)
oh my god
To anyone bumping into this weird bug in 2022 - A quick n easy DIY destroy-on-close : Just use v-if on the template your sending inside the el-dialog with the same property used to open it :)
thanks, that worked !! Yay!!