Element-plus弹出框popover,使用自定义的图标选择组件
自定义的图标选择组件是若依的项目的
1. 若依的图标选择组件
- js文件,引入所有的svg图片
let icons = []
// 注意这里的路径,一定要是自己svg图片的路径
const modules = import.meta.glob('./../../assets/icons/svg/*.svg');
for (const path in modules) {
const p = path.split('assets/icons/svg/')[1].split('.svg')[0];
icons.push(p);
}
export default icons
- vue组件
- 自定义的
SvgIcon
组件,每个人定义的方式都不用,这里重要的就是name
属性:图片的名字 - defineProps:
activeIcon
: 用于返显用户已经选择或者原本就存在的图标 - meit:订阅selected事件,发送用户当前选择的图标
- defineExpose:
reset
方法,向外抛出方法,在父组件中可以清除搜索框中的内容
- 自定义的
<template>
<div class="icon-body">
<el-input
v-model="iconName"
class="icon-search"
clearable
placeholder="请输入图标名称"
@clear="filterIcons"
@input="filterIcons"
>
<template #suffix><SvgIcon name="search"/></template>
</el-input>
<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 }]">
<!--自定义的SvgIcon组件,每个人定义的方式都不用,这里重要的就是name属性:图片的名字-->
<SvgIcon :name="item" class-name="icon" style="height: 25px;width: 16px;"/>
<span>{{ item }}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import icons from './requireIcons'
import SvgIcon from '@/components/svgicon/SvgIcon.vue'
// activeIcon: 用于返现用户已经选择的图标
const props = defineProps({
activeIcon: {
type: String
}
});
const iconName = ref('');
const iconList = ref(icons);
// 订阅selected时间,发送用户当前选择的图标
const emit = defineEmits(['selected']);
// 通过js文件中的方法,将icon/svg文件夹中的图标的名字取出来
function filterIcons() {
iconList.value = icons
if (iconName.value) {
iconList.value = icons.filter(item => item.indexOf(iconName.value) !== -1)
}
}
function selectedIcon(name) {
emit('selected', name)
document.body.click()
}
function reset() {
iconName.value = ''
iconList.value = icons
}
// 向外抛出方法:在父组件中可以清除搜索框中的内容
defineExpose({
reset
})
</script>
<style lang='scss' scoped>
.icon-body {
width: 100%;
padding: 10px;
.icon-search {
position: relative;
margin-bottom: 5px;
width: 50%;
}
.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. 在项目中引入组件
引入组件
<IconSelect @selected="iconSelected" ref="iconSelect" :activeIcon="formData.icon"/>
@selected="iconSelected"
:接收子组件发送的事件,图标被选中:activeIcon="formData.icon"
:给子组件传递图标,比如在修改数据时,数据中原本就存在图标ref="iconSelect"
:使用子组件的实例,调用子组件抛出的方法
<el-popover
placement="bottom-start"
:width="200"
trigger="click"
>
<!-- popover弹出框的插槽,这个插槽的决定了弹出框在页面显示的效果,这里显示的是input输入框 -->
<template #reference>
<el-input v-model="formData.icon" placeholder="请选择图标" clearable @clear="clearIconInput">
<!-- input的插槽,input框前面显示的图标 -->
<template #prefix>
<svg-icon v-if="formData.icon" :name="formData.icon" />
<svg-icon v-else name="search" />
</template>
</el-input>
</template>
<!-- popover弹出框的插槽,这个插槽决定弹出框弹出后显示的内容,这里显示的是IconSelect组件 -->
<template #default>
<!-- 弹出框的内容是自定义组件 -->
<IconSelect style="background-color: #fff;width:500px;border:1px black solid" @selected="iconSelected" ref="iconSelect" :activeIcon="formData.icon"/>
</template>
</el-popover>
<script setup>
const formData = reactive({
icon: undefined,
})
// 子组件的ref,用户调用子组件中defineExpose暴露的方法
const iconSelectRef = useTemplateRef("iconSelect")
// 子组件IconSelect通过emit发送的订阅消息
const iconSelected = (name) => {
formData.icon = name
}
// 调用子组件iconSelect的reset方法
const clearIconInput = () => {
formData.icon = undefined
iconSelectRef.value.reset()
}
</script>