1. 展示
2. 实现
2.1 组件实现
src\components\IconSelect\index.vue
<template>
<div class="icon-body">
<!-- 头部输入框 -->
<el-input v-model="name" class="icon-search" clearable placeholder="请输入图标名称" @clear="filterIcons" @input="filterIcons">
<template #suffix>
<el-icon class="el-input__icon"><search /></el-icon>
</template>
</el-input>
<!-- 显示所有的icon和名字的容器 -->
<div class="icon-list">
<div class="list-container">
<div v-for="(item, index) in iconList" class="icon-item-wrapper" :key="index" @click="selectedIcon(item)">
<div :class="['icon-item', { active: activeIcon === item }]">
<!-- 通过组件显示图标 -->
<svg-icon :name="item" width="16px" height="25px"></svg-icon>
<span>{{ item }}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import icons from './requestIcon'
import { ref,defineProps,defineEmits } from 'vue';
// 声明事件
const emit = defineEmits(['selected'])
defineProps({
activeIcon: String
})
const name = ref();
let iconList = icons;
//console.log("selecticon icons = ", icons)
function filterIcons() {
//console.log("filterIcons == ======")
iconList = icons
if (name.value) {
iconList = iconList.filter(item => item.includes(name.value))
}
}
function selectedIcon(name) {
emit('selected',name)
document.body.click()
}
function reset() {
name.value = ''
iconList.value = icons
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.icon-body {
width: 100%;
padding: 10px;
.icon-search {
position: relative;
margin-bottom: 5px;
}
.icon-list {
height: 200px;
overflow: auto;
.list-container {
display: flex;
flex-wrap: wrap;
.icon-item-wrapper {
width: calc(100% / 3);
height: 25px;
line-height: 25px;
cursor: pointer;
display: flex;
.icon-item {
display: flex;
max-width: 100%;
height: 100%;
padding: 0 5px;
&:hover {
background: #ececec;
border-radius: 5px;
}
.icon {
flex-shrink: 0;
}
span {
display: inline-block;
vertical-align: -0.15em;
fill: currentColor;
padding-left: 2px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.icon-item.active {
background: #ececec;
border-radius: 5px;
}
}
}
}
}
</style>
2.2 图标加载
src\components\IconSelect\requestIcon.ts
const iconsVite = import.meta.glob('../../assets/icons/svg/*.svg')
// icon数组,最终导出
let icons = [];
// 正则表达式,匹配所有的svg文件
const re = /\.\/(.*)\.svg/
// 循环,根据正则表达式,匹配值图标
for (const icon in iconsVite) {
// 只获取图标的名字
let name = icon.match(re)[1].substring(icon.match(re)[1].lastIndexOf('/') + 1)
icons.push(name)
}
//console.log("requestIcon icons = ", icons)
export default icons
注:其依赖于前部分自定义图标组件
3. 使用示例
// 导入图标选择组件
import IconSelect from '@/components/IconSelect/index.vue'
<el-form-item label="菜单图标" prop="icon">
<el-popover placement="bottom-start" :width="540" trigger="click">
<template #reference>
<!-- 通过插槽实现图标选择,默认是一个有图标的输入框 -->
<el-input v-model="form.icon" placeholder="请选择图标">
<template #prefix>
<!-- 判断是否选中了icon -->
<svg-icon v-if="form.icon" slot="prefix" :name="form.icon" width="16px"
height="16px" />
<!-- 如果未选中,显示默认的搜索图标 -->
<el-icon v-else class="el-input__icon">
<search />
</el-icon>
</template>
</el-input>
</template>
<!-- 显示选择图标的组件 -->
<IconSelect ref="iconSelect" @selected="handleSelect" :active-icon="form.icon" />
</el-popover>
</el-form-item>