优雅封装:Vue3 + Element Plus 智能紧凑型搜索组件开发实践

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
    },
    
    // 更多配置项...
  ];
});

设计优势分析

  1. 用户体验提升

    • 高频操作零点击访问
    • 复杂操作两步完成(展开->操作)
    • 视觉层次分明,重点突出
  2. 开发效率提升

    • 配置化开发,减少重复代码
    • 统一交互模式,降低学习成本
    • 组件解耦,便于维护
  3. 性能优化

    • 条件渲染避免不必要的DOM节点
    • 按需加载联动数据
    • 智能高度计算避免页面跳动
  4. 扩展性强

    • 支持多种表单类型
    • 易于添加新表单控件
    • 支持复杂联动场景

实际应用场景

典型使用场景

  1. CRM系统的客户筛选
  2. ERP系统的订单查询
  3. 数据分析平台的多维筛选
  4. 后台管理系统的日志查询

场景示例:线索管理系统

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. 主搜索项选择:选择最常用、最核心的1-2个字段作为主搜索项
  2. 默认值设置:在父组件mounted中设置合理的默认值
  3. 联动优化:对数据量大的联动使用防抖请求

总结与展望

本文介绍了一款基于Vue3和Element Plus的智能紧凑型搜索组件,它通过创新的设计解决了后台管理系统中的搜索条件过多问题。该组件具有以下特点:

  1. 配置驱动:通过JSON配置生成搜索表单
  2. 智能分组:自动按行分组展示搜索条件
  3. 强大联动:支持字段间复杂联动关系
  4. 响应式设计:完美适配不同屏幕尺寸
  5. 用户体验优先:平衡了功能丰富性和界面简洁性

未来可能的改进方向:

  • 添加自定义插槽支持更复杂的表单控件
  • 集成表单验证功能
  • 增加搜索条件保存/加载功能
  • 支持可视化配置面板

完整代码示例

组件内容

父组件调用

成果展示

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

相关推荐
崔庆才丨静觅11 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606112 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了12 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅12 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅12 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅13 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment13 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅13 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊13 小时前
jwt介绍
前端
爱敲代码的小鱼13 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax