實現一個篩選框,點擊篩選按鈕出現彈窗,彈窗內有選擇框/輸入框/單選框等等,底部有重置/確定兩個按鈕。
需求:
- 點擊篩選外部其他位置可以關閉彈窗,關閉彈窗后已編輯的數據不保存,
- 點擊確定按鈕關閉彈窗;
- 點擊重置按鈕不關閉彈窗;
- 彈窗打開時,點擊篩選按鈕彈窗關閉,彈窗關閉時,點擊篩選按鈕彈窗打開;
如下圖所示:
圖一
實現方法:
完整代碼在最下方,展示的是方法二的完整代碼,可以根據自己需求來修改對應的邏輯。
注意:兩種方法都需要把有下拉框的組件中加上: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>