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确保图标比例不失真
🛠️ 扩展建议
- 图标本地化 :若项目对网络依赖敏感,可将 SVG 图标下载后放入
assets/icons目录,通过import引入。 - 动态图标组件 :可封装
<DimensionIcon name="user" />组件,内部根据 name 渲染不同图标。 - 性能优化 :当选项非常多时,可考虑虚拟滚动(Element Plus 的
virtualized属性)。 - 国际化支持 :
cnName可替换为$t('dimension.user_id')实现多语言。
✅ 总结
通过 Element Plus 的插槽机制(特别是 #label 插槽),我们可以轻松实现高度定制化的下拉选择器。结合语义化图标,不仅提升了界面美观度,也增强了用户对字段含义的理解。
这种"带图标的多选维度选择器"非常适合用在:
- 报表配置面板
- 数据看板筛选器
- OLAP 查询构建器
- 自助分析工具
希望本文对你有帮助!欢迎点赞、收藏、评论交流 👇