Vue3 + Element Plus 智能紧凑型搜索组件深度解析
引言:解决后台管理系统搜索痛点
在后台管理系统开发中,我们经常面临一个共同挑战:如何优雅地处理大量搜索条件。传统的解决方案要么将所有条件平铺展示(导致页面冗长),影响页面美观如下图
要么全部折叠在高级搜索中(增加用户操作成本)。
本文将深入解析一款智能紧凑型搜索组件,它通过创新设计解决了这一痛点。
组件设计思路
核心设计理念
- 主次分离:高频搜索项外露,次要条件收纳
- 配置驱动:通过JSON配置动态生成表单
- 智能联动:支持字段间联动关系
- 空间优化:紧凑布局节省页面空间
- 用户体验:一键展开/收起,操作流畅
架构示意图
css
┌──────────────────────────────────────────────┐
│ 筛选 [展开图标] [主搜索输入框] [搜索] [重置] │
├──────────────────────────────────────────────┤
│ ▼ 展开面板 │
│ ┌────────────┬────────────┬────────────┐ │
│ │ 条件1标签 │ 条件2标签 │ 条件3标签 │ │
│ │ 条件1控件 │ 条件2控件 │ 条件3控件 │ │
│ └────────────┴────────────┴────────────┘ │
│ ┌────────────┬────────────┬────────────┐ │
│ │ 条件4标签 │ 条件5标签 │ 条件6标签 │ │
│ │ 条件4控件 │ 条件5控件 │ 条件6控件 │ │
│ └────────────┴────────────┴────────────┘ │
└──────────────────────────────────────────────┘
组件实现深度解析
1. 智能搜索条件分发
通过 ifShow
属性区分主次搜索条件,为true表示在主面板中直接展示搜索条件:
javascript
const computedOnlyShowInputObject = computed(() => {
return props.searchConfig.find(i => i.ifShow === true);
});
在模板中动态渲染主搜索项:
vue
<el-input
v-model="queryParams[computedOnlyShowInputObject.prop]"
:placeholder="computedOnlyShowInputObject.placeholder"
/>
2. 动态表单渲染引擎
组件支持多种表单类型,通过配置动态渲染:
vue
<template v-if="item.type === 'daterange'">
<!-- 日期范围选择器 -->
</template>
<template v-else-if="item.type === 'input'">
<!-- 文本输入框 -->
</template>
<template v-else-if="item.type === 'radio'">
<!-- 单选按钮组 -->
</template>
<!-- 更多类型... -->
3. 条件分组算法
将搜索条件按每行3个分组展示:
javascript
const searchRows = computed(() => {
const rows = [];
const visibleItems = props.searchConfig.filter(i => !i.ifShow);
for (let i = 0; i < visibleItems.length; i += 3) {
rows.push(visibleItems.slice(i, i + 3));
}
return rows;
});
4. 智能联动系统
通过配置实现字段间联动:
javascript
{
label: '来源渠道',
prop: 'bidChannelId',
type: 'radio',
linkage: {
resetFields: ['bidAccountId'],
onChange: async (val) => {
await getbidAccountList(val);
queryParams.bidAccountId = undefined;
}
}
}
联动监听实现:
javascript
watch(
() => props.queryParams[item.prop],
async (newVal) => {
if (newVal) {
await item.linkage?.onChange?.(newVal);
} else {
item.linkage?.resetFields?.forEach(field => {
props.queryParams[field] = undefined;
});
}
},
{ deep: true }
);
5. 智能高度计算
根据屏幕高度动态调整展开面板高度:
javascript
const computedHeight = computed(() => {
const bodyHeight = document.body.offsetHeight;
return Math.max(bodyHeight - 240, 300) + 'px';
});
6. 交互优化细节
点击外部关闭面板:
javascript
const handleClickOutside = (event: MouseEvent) => {
const target = event.target as HTMLElement;
const isDatePicker = target.closest('.el-picker__panel') ||
target.closest('.el-date-range-picker') ||
target.closest('.el-popper');
if (showSearch.value && searchContainer.value &&
!searchContainer.value.contains(target) && !isDatePicker) {
showSearch.value = false;
}
};
重置功能:
javascript
const resetQuery = () => {
// 重置基础字段
Object.keys(props.queryParams).forEach(key => {
props.queryParams[key] = Array.isArray(props.queryParams[key]) ? [] : undefined;
});
// 处理联动重置
props.searchConfig.forEach(item => {
item.onReset?.();
item.linkage?.resetFields?.forEach(field => {
props.queryParams[field] = undefined;
});
});
emit('reset');
};
父组件集成示例
1. 基本使用
vue
<div class="search-container mb-20px">
<CompactSearch
:queryParams="queryParams"
:searchConfig="searchConfig"
:shortCuts="shortCuts"
@query="handleQuery"
@reset="resetQuery"
/>
<el-button type="primary" @click="openForm('create')">
<Icon icon="ep:plus" class="mr-5px" />
新增
</el-button>
</div>
2. 搜索配置详解
javascript
const searchConfig = computed(() => {
return [
// 主搜索项(始终显示)通过ifShow: true 控制
{
label: '线索名称',
prop: 'keyword',
type: 'input',
placeholder: '线索名称/手机号/微信/qq',
ifShow: true
},
// 次要搜索项(在展开面板中显示)
{
label: '发布时间',
prop: 'publishTime',
type: 'daterange',
ifShow: false,
},
// 复选框示例
{
label: '线索状态',
prop: 'clueStatus',
type: 'checkbox',
options: getIntDictOptions(DICT_TYPE.CRM_CLUE_STATUS),
ifShow: false,
},
// 联动字段示例
{
label: '来源渠道',
prop: 'bidChannelId',
type: 'radio',
options: bidOriginList.value.map(item => ({
value: item.id,
label: item.name
})),
linkage: {
resetFields: ['bidAccountId'],
onChange: async (val) => {
await getbidAccountList(val);
queryParams.bidAccountId = undefined;
}
},
ifShow: false,
},
//非关联关系直接通过接口动态获取options
{
label: '来源账户',
prop: 'bidAccountId',
type: 'radio',
options: bidAccountList.value.map((item) => ({
value: item.id,
label: item.name
})),
ifShow: false
},
// 更多配置项...
];
});
设计优势分析
-
用户体验提升
- 高频操作零点击访问
- 复杂操作两步完成(展开->操作)
- 视觉层次分明,重点突出
-
开发效率提升
- 配置化开发,减少重复代码
- 统一交互模式,降低学习成本
- 组件解耦,便于维护
-
性能优化
- 条件渲染避免不必要的DOM节点
- 按需加载联动数据
- 智能高度计算避免页面跳动
-
扩展性强
- 支持多种表单类型
- 易于添加新表单控件
- 支持复杂联动场景
实际应用场景
典型使用场景
- CRM系统的客户筛选
- ERP系统的订单查询
- 数据分析平台的多维筛选
- 后台管理系统的日志查询
场景示例:线索管理系统
javascript
const searchConfig = computed(() => {
return [
{
label: '线索名称',
prop: 'keyword',
type: 'input',
placeholder: '线索名称/手机号/微信/qq',
ifShow: true //唯一键值 判断是在展开的dialog中展示还是在输入框中直接展示
},
{
label: '发布时间',
prop: 'publishTime',
type: 'daterange',
ifShow: false
},
{
label: '线索状态',
prop: 'clueStatus',
type: 'checkbox',
options: getIntDictOptions(DICT_TYPE.CRM_CLUE_STATUS),
ifShow: false
},
{
label: '来源渠道',
prop: 'bidChannelId',
type: 'radio',
options: bidOriginList.value.map((item) => ({
value: item.id,
label: item.name
})),
linkage: {
// 当渠道变化时需要重置的字段
resetFields: ['bidAccountId'],
// 当渠道变化时调用的方法
onChange: async (val) => {
await getbidAccountList(val)
queryParams.bidAccountId = undefined
}
},
ifShow: false
},
{
label: '来源账户',
prop: 'bidAccountId',
type: 'radio',
options: bidAccountList.value.map((item) => ({
value: item.id,
label: item.name
})),
ifShow: false
},
{
label: '超时响应',
prop: 'overtimeFlag',
type: 'radio',
options: [
{ label: '是', value: true },
{ label: '否', value: false }
],
ifShow: false
},
{
label: '地区',
prop: 'areaId',
type: 'treeSelect',
data: areaList.value,
props: defineProps,
ifShow: false
},
{
label: '接收公司',
prop: 'receiveTenantId',
type: 'select',
options: companyList.value.map((item) => ({
value: item.id,
label: item.name
})),
ifShow: false
}
]
})
最佳实践与技巧
配置技巧
- 主搜索项选择:选择最常用、最核心的1-2个字段作为主搜索项
- 默认值设置:在父组件mounted中设置合理的默认值
- 联动优化:对数据量大的联动使用防抖请求
总结与展望
本文介绍了一款基于Vue3和Element Plus的智能紧凑型搜索组件,它通过创新的设计解决了后台管理系统中的搜索条件过多问题。该组件具有以下特点:
- 配置驱动:通过JSON配置生成搜索表单
- 智能分组:自动按行分组展示搜索条件
- 强大联动:支持字段间复杂联动关系
- 响应式设计:完美适配不同屏幕尺寸
- 用户体验优先:平衡了功能丰富性和界面简洁性
未来可能的改进方向:
- 添加自定义插槽支持更复杂的表单控件
- 集成表单验证功能
- 增加搜索条件保存/加载功能
- 支持可视化配置面板
完整代码示例
组件内容

父组件调用

成果展示


通过本文的深度解析,希望能帮助开发者更好地理解和应用这种智能搜索模式,提升后台管理系统的用户体验和开发效率。