vue3+element-plus,el-popover实现筛选弹窗的方法
实现一个筛选框,点击筛选按钮出现弹窗,弹窗内有选择框/输入框/单选框等等,底部有重置/确定两个按钮。
需求:
- 点击筛选外部其他位置可以关闭弹窗,关闭弹窗后已编辑的数据不保存,
- 点击确定按钮关闭弹窗;
- 点击重置按钮不关闭弹窗;
- 弹窗打开时,点击筛选按钮弹窗关闭,弹窗关闭时,点击筛选按钮弹窗打开;
如下图所示:
图一
实现方法:
完整代码在最下方,展示的是方法二的完整代码,可以根据自己需求来修改对应的逻辑。
注意:两种方法都需要把有下拉框的组件中加上:teleported="false",否则,点击下拉框选择数据后也会关闭弹窗,就不符合需求了。
一、通过ref+hide方法实现
实现步骤:
1、在el-popover设置popoverRef,在点击弹窗内部的确定按钮时,通过popoverRef.value.hide()关闭弹窗;
2、要实现点击弹窗外其他地方,已编辑的数据不保存,用sessionStorage来实现,在点击确定按钮通过sessionStorage把参数保存起来,点击重置,就删除sessionStorage的参数;
3、使用el-popover自带的hide方法,点击弹窗外其他地方后,通过hide方法把已编辑的数据恢复;
const popoverRef = ref<any>(null)// 关闭弹窗
const clickShowFilter = async () => {if (sessionStorage.getItem('filterFormQuery')) {Object.assign(filterForm.value,JSON.parse(sessionStorage.getItem(`filterFormQuery`) || ''))} else {handleCancel('清除')}
}// 重置
const handleCancel = async (type = '') => {filterForm.value = {selectVal: '',inputVal: '',radioVal: '1',dateVal: '',}if (type === '清除') {return false}// 清除筛选参数sessionStorage.removeItem(`filterFormQuery`)// 调用接口
}// 确定
const handleConfirm = async () => {// 关闭弹窗popoverRef.value.hide()// 保存筛选参数sessionStorage.setItem('filterFormQuery', JSON.stringify(filterForm.value))// 调用接口
}
完整代码
二、通过:visible+v-click-outside实现
使用visible手动控制弹窗的显示/隐藏,点击筛选按钮和确定按钮时,可以通过定义的变量来控制弹窗,但是点击空白区域不会自动关闭弹窗,这时候就需要用到Element Plus 提供的
v-click-outside
指令。
1、引入指令:
import { ClickOutside as vClickOutside } from 'element-plus'
2、给el-popover中的reference绑定指令元素
3、定义关闭函数
const handleClickOutside = (event: { target: any }) => {const popoverContent = popoverRef.value?.popperRef?.contentRefif (fillterShow.value && !popoverContent?.contains(event.target)) {fillterShow.value = false}
}
完整代码:
<template><div class="box"><el-popoverref="popoverRef"placement="bottom-start":width="300"trigger="click":teleported="false":visible="fillterShow"><template #reference><div@click="clickShowFilter"v-click-outside="handleClickOutside":disabled="loading"class="filter-button"><span>筛选</span><el-icon :size="14" color="#$008dff"><Filter /></el-icon></div></template><el-formlabel-position="top"label-width="auto":model="filterForm"class="query-box":inline="true"><el-form-item label="选择框:"><el-select:teleported="false"v-model="filterForm.selectVal"placeholder="请选择"><el-option :key="0" label="全部" value="" /><el-option :key="1" label="选择1" :value="1" /><el-option :key="2" label="选择2" :value="2" /></el-select></el-form-item><el-form-item label="输入框:"><el-inputv-model="filterForm.inputVal"placeholder="请输入"suffix-icon="Search"/></el-form-item><el-form-item label="单选框:"><el-radio-group v-model="filterForm.radioVal"><el-radio value="1">单选1</el-radio><el-radio value="2">单选2</el-radio></el-radio-group></el-form-item><el-form-item label="日期选择框:"><el-date-picker:teleported="false"v-model="filterForm.dateVal"type="date"placeholder="日期选择"/></el-form-item><div class="form-button"><el-button :loading="loading" @click="handleCancel()">重置</el-button><el-button :loading="loading" type="primary" @click="handleConfirm">确定</el-button></div></el-form></el-popover></div>
</template>
<script setup lang="ts">
import { ClickOutside as vClickOutside } from 'element-plus'let loading = ref<boolean>(false)interface filterParams {selectVal: stringinputVal: stringradioVal: stringdateVal: string
}
const filterForm = ref<filterParams>({selectVal: '',inputVal: '',radioVal: '1',dateVal: '',
})const popoverRef = ref<any>(null)
// 筛选弹出框开关
const fillterShow = ref<boolean>(false)// 关闭弹窗
const clickShowFilter = async () => {fillterShow.value = !fillterShow.valueif (fillterShow.value) {// 判断之前是否有筛选过的参数,有就把该参数赋值给filterForm.value,没有就初始化(相当于重置)if (sessionStorage.getItem('filterFormQuery')) {Object.assign(filterForm.value,JSON.parse(sessionStorage.getItem(`filterFormQuery`) || ''))} else {handleCancel('清除')}}
}// 重置
const handleCancel = async (type = '') => {filterForm.value = {selectVal: '',inputVal: '',radioVal: '1',dateVal: '',}if (type === '清除') {return false}// 清除筛选参数sessionStorage.removeItem(`filterFormQuery`)// 调用接口
}// 确定
const handleConfirm = async () => {// 关闭弹窗fillterShow.value = false// 保存筛选参数sessionStorage.setItem('filterFormQuery', JSON.stringify(filterForm.value))// 调用接口
}const handleClickOutside = (event: { target: any }) => {const popoverContent = popoverRef.value?.popperRef?.contentRefif (fillterShow.value && !popoverContent?.contains(event.target)) {fillterShow.value = false}
}
</script>
<style lang="scss" scoped>
.box {margin: 16px;background-color: #fff;overflow: auto;height: 100%;padding: 16px;box-sizing: border-box;.filter-button {display: flex;align-items: center;justify-content: center;width: 64px;height: 32px;line-height: 32px;font-size: 14px;font-weight: 400;color: #008dff;cursor: pointer;border: 1px solid #008dff;border-radius: 4px;i {margin-left: 5px;font-size: 14px;}}.query-box {:deep(.el-input) {width: 220px;}:deep(.el-select) {width: 220px;}}.form-button {display: flex;align-items: center;justify-content: flex-end;width: 100%;}
}
</style>