el-select 下拉框支持线上 SVG + 本地图片图标 展示

Vue3 + Element Plus 实现带图标的多选下拉框(附完整代码)

在数据可视化、BI 系统或报表配置页面中,我们经常需要让用户从多个"维度"字段中进行选择。为了提升用户体验和界面美观度,为每个选项添加图标是一个非常实用的设计。

本文将手把手教你使用 Vue 3 + <script setup> 语法 + Element Plus 实现一个支持图标显示、可搜索、可清除的带图标的维度多选下拉框,并展示如何自定义选项标签与下拉项的渲染内容。


🎯 效果预览

  • 支持多选
  • 每个选项左侧带有语义化图标(如用户、日历、地图等)
  • 已选项在输入框中同样显示图标和中文名+英文名
  • 支持搜索过滤
  • 自动排除类型为 "3" 的字段(模拟"指标"字段不作为维度)

💡 技术栈说明

  • Vue 3 :使用 Composition API + <script setup> 语法糖
  • Element Plus<el-select><el-option> 组件
  • Iconify:通过 CDN 动态加载 SVG 图标(无需额外安装图标库)

🧩 完整代码实现

1. 模板部分(Template)

vue 复制代码
<template>
  <div style="padding: 20px; max-width: 600px">
    <h3>带图标的维度多选下拉框</h3>
    <el-select
      v-model="selectedDimensions"
      multiple
      clearable
      filterable
      placeholder="请选择维度"
      class="dimension-select"
    >
      <!-- 自定义已选项的标签显示 -->
      <template #label="{ value }">
        <div class="dimension-option">
          <img :src="getDimensionIcon(value)" class="dimension-icon" />
          <span>{{ getDimensionLabel(value) }}</span>
        </div>
      </template>

      <!-- 下拉选项列表 -->
      <el-option
        v-for="item in dimensionOptions"
        :key="item.columnName"
        :value="item.columnName"
      >
        <div class="dimension-option">
          <img
            :src="getDimensionIcon(item.columnName)"
            class="dimension-icon"
          />
          <span>{{
            item.cnName ? `${item.cnName}(${item.columnName})` : item.columnName
          }}</span>
        </div>
      </el-option>
    </el-select>

    <p style="margin-top: 20px">已选:{{ selectedDimensions }}</p>
  </div>
</template>

✅ 关键点:

  • 使用 #label 插槽自定义已选项的显示内容(带图标)
  • el-option 内部也使用相同结构保持 UI 一致

2. 逻辑部分(Script Setup)

vue 复制代码
<script setup>
import { ref, computed } from "vue";
import { ElSelect, ElOption } from "element-plus";

// 模拟维度/指标字段列表
const measureOptions = ref([
  { columnName: "user_id", cnName: "用户ID", type: "1", icon: "user" },
  {
    columnName: "create_time",
    cnName: "创建时间",
    type: "2",
    icon: "calendar",
  },
  { columnName: "region", cnName: "地区", type: "1", icon: "location" },
  { columnName: "status", cnName: "状态", type: "1", icon: "default" },
]);

// 当前选中的维度
const selectedDimensions = ref([]);

// 过滤出 type !== "3" 的字段作为维度选项(假设 type=3 是指标)
const dimensionOptions = computed(() =>
  measureOptions.value.filter((item) => item.type !== "3")
);

// 获取显示文本
const getDimensionLabel = (columnName) => {
  const dim = measureOptions.value.find((d) => d.columnName === columnName);
  return dim
    ? dim.cnName
      ? `${dim.cnName}(${dim.columnName})`
      : dim.columnName
    : columnName;
};

// 根据 icon 字段映射到实际图标 URL(使用 Iconify 免费 CDN)
const getDimensionIcon = (columnName) => {
  const dim = measureOptions.value.find((d) => d.columnName === columnName);
  const name = dim?.icon || "default";
  const iconMap = {
    user: "https://api.iconify.design/mdi:user.svg",
    calendar: "https://api.iconify.design/mdi:calendar-month.svg",
    location: "https://api.iconify.design/mdi:map-marker.svg",
    default: "https://api.iconify.design/mdi:help-circle.svg",
  };
  return iconMap[name] || iconMap.default;
};
</script>

🔍 说明:

  • type 字段用于区分维度(dimension)和指标(measure),这里仅展示维度
  • 图标通过 Iconify 的 CDN 直接加载 SVG,轻量且无需打包

3. 样式部分(Scoped CSS)

vue 复制代码
<style scoped>
.dimension-select {
  width: 100%;
}

.dimension-option {
  display: flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}

.dimension-icon {
  width: 16px;
  height: 16px;
  object-fit: contain;
  vertical-align: middle;
}
</style>

✨ 小技巧:

  • 使用 gap 替代 margin 更简洁
  • object-fit: contain 确保图标比例不失真

🛠️ 扩展建议

  1. 图标本地化 :若项目对网络依赖敏感,可将 SVG 图标下载后放入 assets/icons 目录,通过 import 引入。
  2. 动态图标组件 :可封装 <DimensionIcon name="user" /> 组件,内部根据 name 渲染不同图标。
  3. 性能优化 :当选项非常多时,可考虑虚拟滚动(Element Plus 的 virtualized 属性)。
  4. 国际化支持cnName 可替换为 $t('dimension.user_id') 实现多语言。

✅ 总结

通过 Element Plus 的插槽机制(特别是 #label 插槽),我们可以轻松实现高度定制化的下拉选择器。结合语义化图标,不仅提升了界面美观度,也增强了用户对字段含义的理解。

这种"带图标的多选维度选择器"非常适合用在:

  • 报表配置面板
  • 数据看板筛选器
  • OLAP 查询构建器
  • 自助分析工具

希望本文对你有帮助!欢迎点赞、收藏、评论交流 👇

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