I'm using the el-popover component from Element-Plus in my Vue project to create a popover effect. Here's the code:
<el-button ref="saveButtonRef" class="misc-button" :loading="saveLoading" @click="OnSheetSave">Save</el-button>
<el-popover ref="savePopoverRef" :virtual-ref="saveButtonRef" :visible="showSaveList" placement="top-start" :width="500" virtual-triggering>
...el-popover Content...
</el-popover>
I want the popover to close when the mouse clicks outside of both the saveButtonRef and savePopoverRef instances. Therefore, I added an event listener:
document.addEventListener('click', handleClickPopoverOutside);
function handleClickPopoverOutside(event) {
if (showSaveList.value) {
const buttonElement = saveButtonRef.value.$el;
const popoverElement = savePopoverRef.value.$el;
if (buttonElement && !buttonElement.contains(event.target) && popoverElement && !popoverElement.contains(event.target)) {
OnSaveSheetPoPoverClose(); // Close Popover Instance
}
}
}
However, this doesn't work as expected. When I click on the savePopoverRef instance, it still triggers the OnSaveSheetPoPoverClose() function. I found that the reason is because savePopoverRef.value.$el returns #text. Is there a way to properly get the root DOM element of the el-popover component, or is there another approach to close the popover when clicking outside of it?
As mentioned above, I want to be able to close the popover by triggering my function OnSaveSheetPoPoverClose() when clicking outside of the saveButtonRef and savePopoverRef instances. And I don't want to change the virtual-ref of savePopoverRef from saveButtonRef, as it would affect my other logic.
For hiding a popup programmatically in Vue, I take a reverse approach to handling the events. It is easier and more general.
window.addEventListener
@click.stop
This way, I can catch the click events that occur outside of the popup, while letting popup content do and process their click event.
Here is a sample demo:
<link rel="stylesheet" href="//unpkg.com/element-plus/dist/index.css" />
<script src="//unpkg.com/vue@3"></script>
<script src="//unpkg.com/element-plus"></script>
<body>
<div id="app">
<el-button
class="misc-button"
@click.stop="toggleDialog"
>
Show Dialog
</el-button>
<el-button
ref="saveButtonRef"
class="misc-button"
:loading="saveLoading"
@click.stop="OnSheetSave"
>
Save
</el-button>
<el-popover
:visible="showSaveList"
placement="top-start"
:width="300"
virtual-triggering
>
<div style="min-width: 100px; min-height: 100px;border: 1px dashed red;" @click.stop>
Your pop-up content goes here. Clicking anywhere on the popup won't close the modal, but clicking outside triggers the event handler and closes the modal
</div>
</el-popover>
</div>
<script>
const App = {
data() {
return {
showSaveList: false,
};
},
methods: {
OnSaveSheetPoPoverClose() {
console.log('OnSaveSheetPoPoverClose got called');
this.toggleDialog(); // hide dialog and remove the event listener
this.OnSheetSave();
},
OnSheetSave(){
console.log('OnSheetSave got called');
},
toggleDialog() {
if (this.showSaveList) {
this.showSaveList = false;
window.removeEventListener('click', this.OnSaveSheetPoPoverClose);
} else {
this.showSaveList = true;
window.addEventListener('click', this.OnSaveSheetPoPoverClose);
}
},
},
};
const app = Vue.createApp(App);
app.use(ElementPlus);
app.mount("#app");
</script>
</body>
There is a Show Dialog
button, which shows the popup and adds the event listener ensuring the OnSaveSheetPoPoverClose
gets called on every click.
To prevent common elements from triggering the OnSaveSheetPoPoverClose
, I stopped their click event (prevent it from propagating) using @click.stop
.
Make sure to remove event listeners at the proper time.