场景介绍
- 后台管理系统有很多功能都需要基于 Element Plus UI 库进行二次封装,以便于简化我们后续的开发。
- 查询条件表单是我们系统中非常常见的功能,我们需要把它封装成一个通用的组件,方便在系统开发中提升开发效率。
- 除了在实现基本查询条件的功能上,还需要实现多条件的折叠和展开功能
- 下面的代码实现是 基于 Vue3 + Typescript + Element Plus实现的,仅供参考
示例效果
- 查询条件收起的状态
- 查询条件展开的状态
实现代码
-
封装查询条件表单组件
SearchForm.vue<template> <div v-if="showSearchBtn" class="search-form-box"> <el-form :inline="true" :model="searchForm" size="default" ref="searchFormRef"> <el-row> <el-col :span="cond.span" v-for="cond in sliceCodList" :key="cond.id"> <el-form-item :label="cond.label + ':'" :prop="cond.prop" class="flex-form-item"> <!-- 输入框 --> <el-input v-if="cond.type === 'input'" v-model="searchForm[cond.prop]" :placeholder="cond.placeholder" clearable /> <!-- 下拉框 --> <el-select v-else-if="cond.type === 'select'" v-model="searchForm[cond.prop]" :placeholder="cond.placeholder" clearable> <el-option v-for="op in cond.optionList" :key="op.value" :label="op.label" :value="op.value" /> </el-select> <!-- 日期组合 --> <el-date-picker v-else-if="cond.type === 'daterange'" v-model="searchForm[cond.prop]" type="daterange" start-placeholder="开始日期" end-placeholder="结束日期" /> <!-- 日期时间 --> <el-date-picker v-else-if="cond.type === 'datetime'" v-model="searchForm[cond.prop]" type="datetime" placeholder="请选择日期时间" style="width: 100%" /> </el-form-item> </el-col> <el-col :span="rSpanCount" class="el-col-wrapper"> <el-form-item class="btn-group-item flex-end"> <el-button type="primary" :icon="Search" @click="search">查询</el-button> <el-button plain :icon="RefreshRight" @click="reset">重置</el-button> <el-button v-show="showFoldBtn" type="primary" link @click="toggleFold"> {{ conditionFold ? "展开" : "收起" }} <el-icon v-if="conditionFold"> <ArrowDown /> </el-icon> <el-icon v-else> <ArrowUp /> </el-icon> </el-button> </el-form-item> </el-col> </el-row> </el-form> </div> </template> <script lang="ts" setup name="searchForm"> import { Search, RefreshRight, ArrowDown, ArrowUp, } from "@element-plus/icons-vue"; import { reactive, ref, computed, onMounted } from "vue"; // 查询条件的类型接口 interface SearchFormInterFace { [key: string]: string | number | []; }; /** * updateTableList 组件外部传入的拉取表格数据的方法 * conditionList 组件外部传入的查询条件的配置列表数据 */ const props = defineProps([ "updateTableList", "conditionList", ]); // 查询条件组件的实例 const searchFormRef = ref(); // 切换展开和收起查询条件 const conditionFold = ref(true); const toggleFold = () => { conditionFold.value = !conditionFold.value; }; // 初始化折叠查询条件的断点,从第几个查询条件开始(默认是从第3个,因为默认配置的span值是6) const initConditionFoldLen = 3; // 展示右侧按钮组(折叠||收起按钮) const showFoldBtn = computed(() => { return props.conditionList.length > initConditionFoldLen; }); // 展示查询条件组件 const showSearchBtn = computed(() => { return props.conditionList.length > 0; }); // 右侧按钮组动态计算的span值 const rSpanCount = computed(() => { let totalSpan = 0; if (initConditionFoldLen > 0) { if (!conditionFold.value) { totalSpan = props.conditionList.reduce((prev: number, next: any) => { return prev + next.span }, 0) } else { const sliceCondList = props.conditionList.slice(0, initConditionFoldLen); totalSpan = sliceCondList.reduce((prev: number, next: any) => { return prev + next.span }, 0) } } else { totalSpan = props.conditionList.reduce((prev: number, next: any) => { return prev + next.span }, 0) } return 24 - (totalSpan % 24); }) // 打印计算出来的,右侧按钮组占的span值,再通过flex布局,flex-end 定位到最右边 console.log(rSpanCount.value, 'rSpanCount@@@'); // 初始化查询条件的列表 const sliceCodList = computed(() => { return props.conditionList.slice( 0, conditionFold.value ? initConditionFoldLen : props.conditionList.length ); }); // 查询条件表单数据 const searchForm = reactive<SearchFormInterFace>({}); // 搜索表单 const search = () => { props.updateTableList({ pageSize: 10, currentPage: 1, ...searchForm, }); }; // 重置搜索 const reset = () => { searchFormRef.value.resetFields(); props.updateTableList({ pageSize: 10, currentPage: 1, ...searchForm, }); }; // 初始化查询条件的值 onMounted(() => { props.conditionList.forEach((cond: any) => { searchForm[cond.prop] = cond.type === "datetimerange" ? [] : ""; }); }); </script> <style lang="scss" scoped> .search-form-box { box-sizing: border-box; box-shadow: var(--el-box-shadow-light); background-color: #fff; border-radius: 4px; padding: 12px; margin-bottom: 12px; .flex-form-item { display: flex; align-items: center; } .el-col-wrapper { display: flex; .btn-group-item { flex: 1; display: flex; :deep(.el-form-item__content) { flex: 1; display: flex; align-items: center; } &.flex-end { :deep(.el-form-item__content) { justify-content: flex-end; } } } } } </style> -
使用查询条件表单组件(引入组件即可)
<template> <SearchForm :updateTableList="updateTableList" :conditionList="conditionList" /> </template> <script lang="ts" setup> import { reactive, ref } from "vue"; // 定义表格数据每项的类型 type tableDataItem = { username: string; age: number; address: string; big: string; color: string; hobby: string; sex: string; school: string; grade: string; }; // 表格加载loading const loading = ref(false); // 表格数据 let tableData = ref<tableDataItem[]>([]); // 表格数据总条数 const total = ref(0); // 查询条件配置项 // type 是查询条件里面的组件类型 如input select等,可以自行添加需要的组件 const conditionList = reactive([ { id: 1, type: "input", label: "用户名称", prop: "username", placeholder: "请输入用户名称", span: 6, }, { id: 2, type: "select", label: "个头大小", prop: "big", placeholder: "请选择个头大小", optionList: [ { label: "大", value: 1, }, { label: "小", value: 0, }, ], span: 6, }, { id: 3, type: "select", label: "性别", prop: "sex", placeholder: "请选择性别", optionList: [ { label: "男", value: 1, }, { label: "女", value: 0, }, ], span: 6, }, { id: 4, type: "input", label: "地址", prop: "address", placeholder: "请输入地址", span: 6, }, { id: 5, type: "datetime", label: "档案时间", prop: "time", span: 6, }, ]); // 请求数据代码仅供参考,这里放自己的业务逻辑 const updateTableList = async (reqParams: any) => { loading.value = true; const { code, data }: any = await reqTableList(reqParams); if (code === 200) { tableData.value = data.list.map((item: tableDataItem) => ({ ...item, bigLabel: item.big ? "大" : "小", sexLabel: item.sex ? "男" : "女", })); total.value = data.total; setTimeout(() => { loading.value = false; }, 1000); } }; </script>