概要
讲解在vue3的项目中封装一个简单好用的图标选择组件。
效果
第一步,准备图标数据
数据太多,大家去项目中看。项目地址https://gitee.com/nideweixiaonuannuande/xt-admin-vue3
第二步,页面与样式编写
<template>
<div>
<el-icon
class="icon-picker"
:class="{ empty: myValue === '' }"
@click="dialogVisible = true"
>
<svg-icon :name="myValue !== '' ? myValue : 'ep:plus'" />
</el-icon>
<xt-dialog v-model="dialogVisible" width="800px" title="选择图标" :show-cancel="false" :show-confirm="false">
<div>
<el-tabs v-model="activeName" tab-position="left">
<el-tab-pane
v-for="item in data"
:key="item.prefix"
:label="item.name"
:name="item.prefix"
>
<div class="flex flex-wrap">
<div
class="border cursor-pointer border-red-300 p-4"
title="删除已选图标"
@click="removeIcon"
>
<el-icon :size="24">
<svg-icon name="ep:delete" />
</el-icon>
</div>
<div
v-for="icon in currentIconList"
:key="icon"
class="border cursor-pointer p-4"
@click="chooseIcon(`${activeName}:${icon}`)"
>
<el-icon :size="24">
<svg-icon :name="`${activeName}:${icon}`" />
</el-icon>
</div>
</div>
</el-tab-pane>
</el-tabs>
<div class="flex mt-4 px-10 justify-end">
<el-pagination
v-model:current-page="pagination.page"
layout="prev, pager, next"
:page-size="pagination.pageSize"
:total="iconList.length"
:pager-count="5"
background
/>
</div>
</div>
</xt-dialog>
</div>
</template>
<style lang="scss" scoped>
.icon-picker {
width: 40px;
height: 40px;
line-height: 36px;
text-align: center;
color: var(--el-text-color-regular);
border: 1px solid var(--el-border-color);
border-radius: 5px;
cursor: pointer;
transition: 0.3s;
font-size: 24px;
vertical-align: middle;
&:hover {
border: 1px solid var(--el-border-color-darker);
}
&.empty {
color: var(--el-text-color-placeholder);
border: 1px dashed var(--el-border-color);
&:hover {
color: var(--el-text-color-regular);
border: 1px solid var(--el-border-color-darker);
}
}
}
</style>
第三步,逻辑编写
<script setup lang="ts">
import data from './data/data.json'
defineOptions({
name: 'IconPicker',
})
const props = withDefaults(defineProps<{
modelValue: string
}>(), {})
const emits = defineEmits(['update:modelValue'])
const myValue = computed({
get() {
return props.modelValue
},
set(value) {
emits('update:modelValue', value)
},
})
// ------------------数据初始化------------------
const activeName = ref(myValue.value.split(':')[0] || data[0].prefix)
const pagination = ref({
page: 1,
pageSize: 49,
})
const iconList = computed(() => {
return data.filter(item => item.prefix === activeName.value)[0].icons
})
const currentIconList = computed(() => {
return iconList.value.slice(
(pagination.value.page - 1) * pagination.value.pageSize,
(pagination.value.page - 1) * pagination.value.pageSize
+ pagination.value.pageSize,
)
})
// ------------------选择图标相关------------------
const dialogVisible = ref(false)
function chooseIcon(val: string) {
myValue.value = val
dialogVisible.value = false
}
function removeIcon() {
myValue.value = ''
dialogVisible.value = false
}
</script>