当前位置: 首页 > news >正文

vue3+element-plus,el-popover实现筛选弹窗的方法

实现一个筛选框,点击筛选按钮出现弹窗,弹窗内有选择框/输入框/单选框等等,底部有重置/确定两个按钮。

需求:

  1. 点击筛选外部其他位置可以关闭弹窗,关闭弹窗后已编辑的数据不保存,
  2. 点击确定按钮关闭弹窗;
  3. 点击重置按钮不关闭弹窗;
  4. 弹窗打开时,点击筛选按钮弹窗关闭,弹窗关闭时,点击筛选按钮弹窗打开;

如下图所示:

图一

实现方法:

完整代码在最下方,展示的是方法二的完整代码,可以根据自己需求来修改对应的逻辑。

注意:两种方法都需要把有下拉框的组件中加上: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>

http://www.lryc.cn/news/612374.html

相关文章:

  • ACL 2025 Oral|Evaluation Agent:面向视觉生成模型的高效可提示的评估框架
  • 【关于Java的对象】
  • C++、STL面试题总结(二)
  • Android14的QS面板的加载解析
  • 【android bluetooth 协议分析 03】【蓝牙扫描详解 4】【BR/EDR扫描到设备后如何上报给app侧】
  • 力扣137:只出现一次的数字Ⅱ
  • 【计算机网络 | 第4篇】分组交换
  • Javascript/ES6+/Typescript重点内容篇——手撕(待总结)
  • Spring之【初识AOP】
  • hf的国内平替hf-mirror
  • IAR软件中测量函数执行时间
  • 开发笔记 | 接口与抽象基类说明以及对象池的实现
  • 机器学习 朴素贝叶斯
  • 【普通地质学】地球的物质组成
  • iOS混淆工具有哪些?在集成第三方 SDK 时的混淆策略与工具建议
  • MEMS陀螺仪如何在复杂井下环境中保持精准测量?
  • 以此芯p1芯片为例研究OpenHarmony上GPU (Vulkan) 加速在深度学习推理中的价值
  • n8n Slack credentials(n8n slack凭证配置步骤)(API access token)
  • Datawhale AI 夏令营:RAG多模态检索(Baseline解读)
  • 解决启动docker报错Cannot connect to the Docker daemon问题
  • Windows 如何上架 iOS 应用?签名上传全流程 + 工具推荐
  • 使用CRC32爆破ZIP压缩包内小文件内容的技术解析
  • app-3
  • Python面试题及详细答案150道(01-15) -- 基础语法篇
  • 译 | 在 Python 中从头开始构建 Qwen-3 MoE
  • 三轴云台之机械结构篇
  • ubuntu server 工业环境部署手册[2025-08-06]
  • 查看ubuntu server 的基本信息
  • Node.js从入门到精通完整指南
  • 服务器重启后mysql5.7启动失败问题