引言
本文主要使用element Plus 以及 TDesign来说明弹出层的三种打开方式,并且给出各个方式的一些不足点,以及一种较完美的解决方案。
方法一 使用组件自带的触发方式,悬浮 和 点击
element plus 弹出层的悬浮展示弹出层,这种这做法的弊端是想要在弹出层做完操作时不能立马隐藏弹窗。可以看到我选择了11月7日,我想要的效果是我点击之后,这个弹出层能够隐藏。触发方式为点击时也有相同的问题。
相应的代码部分
<template>
<div>
<el-popover style="width: 360px">
<div class="date-picker-panel-border">
<t-date-picker-panel v-model="date" :on-change="handleChange" />
</div>
<template #reference>
<div style="width: 32px; margin: 40px auto">
<CalendarIcon size="32" />
</div>
</template>
</el-popover>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import dayjs from "dayjs";
//
import { CalendarIcon } from "tdesign-icons-vue-next";
const date = dayjs().format("YYYY-MM-DD");
const handleChange = () => {};
</script>
:global(.el-popper) {
width: 300px !important;
}
方法二 使用组件的visible属性,通过这个绑定的true或者false的值来进行控制显隐。
这种做法相较于上述做法无法进行点击弹窗之外进行隐藏弹出层。但可以在改变日期之后隐藏弹出层,具体效果如下:
相应的代码部分
<template>
<div>
<el-popover :visible="visible">
<div class="date-picker-panel-border">
<t-date-picker-panel v-model="date" :on-change="handleChange" />
</div>
<template #reference>
<div style="width: 32px; margin: 40px auto" @click="visible = true">
<CalendarIcon size="32" />
</div>
</template>
</el-popover>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import dayjs from "dayjs";
//
import { CalendarIcon } from "tdesign-icons-vue-next";
const visible = ref(false);
const date = dayjs().format("YYYY-MM-DD");
const handleChange = (value) => {
console.log(value);
visible.value = false;
};
</script>
:global(.el-popper) {
width: 300px !important;
}
较完美的解决方法
- 在onMounted 方法当中注册一个点击事件,在上方js当中加入以下代码,如下所示:
onMounted(() => {
document.addEventListener("click", handleClose);
});
const handleClose = () => {
visible.value = false;
};
- 这样可以实现在点击弹出层其他位置时隐藏弹出层。但是因为事件冒泡原理,我们在点击打开弹出层时会出现先打开弹出,然后冒泡到handleClose中弹出层又立马关闭。效果图如下:
3. 添加阻止冒泡,两个地方,第一打开弹窗的点击方法。
<template #reference>
<div style="width: 32px; margin: 40px auto" @click.stop="visible = true">
<CalendarIcon size="32" />
</div>
</template>
第二个地方,更改日期,注意由于更改日期是change方法,他没有.stop修饰词所以我们要另辟蹊径。在日期选择器的外层div中添加@click.stop,这样change方法往上冒泡就到了外层div,而外层div又禁止冒泡所以就被阻断了。
<div class="date-picker-panel-border" @click.stop>
<t-date-picker-panel v-model="date" :on-change="handleChange" />
</div>
最后大家看看效果:
结论
以后遇到点击弹窗之外能够关闭弹窗都可以参考这种方法。关键就是这两步,然后注意事件冒泡就好了
onMounted(() => {
document.addEventListener("click", handleClose);
});
const handleClose = () => {
visible.value = false;
};
最后附上源码
<template>
<div>
<el-popover :visible="visible">
<div class="date-picker-panel-border" @click.stop>
<t-date-picker-panel v-model="date" :on-change="handleChange" />
</div>
<template #reference>
<div
style="width: 32px; margin: 40px auto"
@click.stop="visible = true"
>
<CalendarIcon size="32" />
</div>
</template>
</el-popover>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from "vue";
import dayjs from "dayjs";
//
import { CalendarIcon } from "tdesign-icons-vue-next";
const visible = ref(false);
const date = dayjs().format("YYYY-MM-DD");
const handleChange = (value) => {
console.log(value);
visible.value = false;
};
onMounted(() => {
document.addEventListener("click", handleClose);
});
const handleClose = () => {
visible.value = false;
};
</script>
:global(.el-popper) {
width: 300px !important;
}