最近在做自己的开发平台,发现目前Antd和Element都没有提供图标选择器,所以自己写一个,跟el-input一样可以双向绑定
弹窗组件使用的Element-Plus的Dialog组件,图标感觉还是Antd的好看一些,所以这里引用的Antd的图标,当然可以引用其他家的图标
1. main.ts中全局注册所有图标组件
import * as antIcons from '@ant-design/icons-vue' const app = createApp(App); // 全局注册图标 Object.keys(antIcons).forEach((key: string) => { app.component(key, antIcons[key as keyof typeof antIcons]) })
2. 封装IconPicker.vue图标选择器组件
<template> <div class="icon-picker" @click="openPicker"> <div class="icon-picker-icon-name">{{ modelValue == '' || modelValue == null || modelValue == undefined ? '点击选择图标' : modelValue }}</div> <div class="icon-picker-icon"> <component v-if="modelValue != '' && modelValue != null && modelValue != undefined" :is="modelValue" /> </div> </div> <el-dialog v-model="pickerVisible" title="图标选择器" destroy-on-close width="970"> <el-input class="icon-picker-search" v-model="searchValue" placeholder="搜索图标" @change="searchIcon"></el-input> <el-tabs v-model="typeTab" type="border-card"> <el-tab-pane class="icon-picker-tab" label="全部" name="all"> <div class="icon-content"> <div v-for="icon in all" :key="icon" class="icon-item" @click="checkIcon(icon)"> <component :is="icon"></component> </div> </div> </el-tab-pane> <el-tab-pane class="icon-picker-tab" label="方向性图标" name="direction"> <div class="icon-content"> <div v-for="icon in direction" :key="icon" class="icon-item" @click="checkIcon(icon)"> <component :is="icon"></component> </div> </div> </el-tab-pane> <el-tab-pane class="icon-picker-tab" label="提示建议性图标" name="prompt"> <div class="icon-content"> <div v-for="icon in prompt" :key="icon" class="icon-item" @click="checkIcon(icon)"> <component :is="icon"></component> </div> </div> </el-tab-pane> <el-tab-pane class="icon-picker-tab" label="编辑类图标" name="edit"> <div class="icon-content"> <div v-for="icon in edit" :key="icon" class="icon-item" @click="checkIcon(icon)"> <component :is="icon"></component> </div> </div> </el-tab-pane> <el-tab-pane class="icon-picker-tab" label="数据类图标" name="data"> <div class="icon-content"> <div v-for="icon in data" :key="icon" class="icon-item" @click="checkIcon(icon)"> <component :is="icon"></component> </div> </div> </el-tab-pane> <el-tab-pane class="icon-picker-tab" label="品牌和标识" name="brand"> <div class="icon-content"> <div v-for="icon in brand" :key="icon" class="icon-item" @click="checkIcon(icon)"> <component :is="icon"></component> </div> </div> </el-tab-pane> <el-tab-pane class="icon-picker-tab" label="网站通用图标" name="common"> <div class="icon-content"> <div v-for="icon in common" :key="icon" class="icon-item" @click="checkIcon(icon)"> <component :is="icon"></component> </div> </div> </el-tab-pane> </el-tabs> </el-dialog> </template> <script lang="ts" setup> import { ref } from 'vue' // 双向绑定属性 const props = defineProps({ modelValue: { type: String, default: '' } }) const emit = defineEmits(['update:modelValue']) // 弹窗显示 const pickerVisible = ref(false); // 查询值 const searchValue = ref(); // 方向性图标 const directionIcon = ['StepBackwardOutlined', 'StepForwardOutlined', 'FastBackwardOutlined', 'FastForwardOutlined', 'ShrinkOutlined', 'ArrowsAltOutlined', 'DownOutlined', 'UpOutlined', 'LeftOutlined', 'RightOutlined', 'CaretUpOutlined', 'CaretDownOutlined', 'CaretLeftOutlined', 'CaretRightOutlined', 'UpCircleOutlined', 'DownCircleOutlined', 'LeftCircleOutlined', 'RightCircleOutlined', 'DoubleRightOutlined', 'DoubleLeftOutlined', 'VerticalLeftOutlined', 'VerticalRightOutlined', 'VerticalAlignTopOutlined', 'VerticalAlignMiddleOutlined', 'VerticalAlignBottomOutlined', 'ForwardOutlined', 'BackwardOutlined', 'RollbackOutlined', 'EnterOutlined', 'RetweetOutlined', 'SwapOutlined', 'SwapLeftOutlined', 'SwapRightOutlined', 'ArrowUpOutlined', 'ArrowDownOutlined', 'ArrowLeftOutlined', 'ArrowRightOutlined', 'PlayCircleOutlined', 'UpSquareOutlined', 'DownSquareOutlined', 'LeftSquareOutlined', 'RightSquareOutlined', 'LoginOutlined', 'LogoutOutlined', 'MenuFoldOutlined', 'MenuUnfoldOutlined', 'BorderBottomOutlined', 'BorderHorizontalOutlined', 'BorderInnerOutlined', 'BorderOuterOutlined', 'BorderLeftOutlined', 'BorderRightOutlined', 'BorderTopOutlined', 'BorderVerticleOutlined', 'PicCenterOutlined', 'PicLeftOutlined', 'PicRightOutlined', 'RadiusBottomleftOutlined', 'RadiusBottomrightOutlined', 'RadiusUpleftOutlined', 'RadiusUprightOutlined', 'FullscreenOutlined', 'FullscreenExitOutlined'] // 提示建议性图标 const promptIcon = ['QuestionOutlined', 'QuestionCircleOutlined', 'PlusOutlined', 'PlusCircleOutlined', 'PauseOutlined', 'PauseCircleOutlined', 'MinusOutlined', 'MinusCircleOutlined', 'PlusSquareOutlined', 'MinusSquareOutlined', 'InfoOutlined', 'InfoCircleOutlined', 'ExclamationOutlined', 'ExclamationCircleOutlined', 'CloseOutlined', 'CloseCircleOutlined', 'CloseSquareOutlined', 'CheckOutlined', 'CheckCircleOutlined', 'CheckSquareOutlined', 'ClockCircleOutlined', 'WarningOutlined', 'IssuesCloseOutlined', 'StopOutlined'] // 编辑类图标 const editIcon = ['EditOutlined', 'FormOutlined', 'CopyOutlined', 'ScissorOutlined', 'DeleteOutlined', 'SnippetsOutlined', 'DiffOutlined', 'HighlightOutlined', 'AlignCenterOutlined', 'AlignLeftOutlined', 'AlignRightOutlined', 'BgColorsOutlined', 'BoldOutlined', 'ItalicOutlined', 'UnderlineOutlined', 'StrikethroughOutlined', 'RedoOutlined', 'UndoOutlined', 'ZoomInOutlined', 'ZoomOutOutlined', 'FontColorsOutlined', 'FontSizeOutlined', 'LineHeightOutlined', 'DashOutlined', 'SmallDashOutlined', 'SortAscendingOutlined', 'SortDescendingOutlined', 'DragOutlined', 'OrderedListOutlined', 'UnorderedListOutlined', 'RadiusSettingOutlined', 'ColumnWidthOutlined', 'ColumnHeightOutlined'] // 数据类图标 const dataIcon = ['AreaChartOutlined', 'PieChartOutlined', 'BarChartOutlined', 'DotChartOutlined', 'LineChartOutlined', 'RadarChartOutlined', 'HeatMapOutlined', 'FallOutlined', 'RiseOutlined', 'StockOutlined', 'BoxPlotOutlined', 'FundOutlined', 'SlidersOutlined'] // 品牌和标识 const brandIcon = ['AndroidOutlined', 'AppleOutlined', 'WindowsOutlined', 'IeOutlined', 'ChromeOutlined', 'GithubOutlined', 'AliwangwangOutlined', 'DingdingOutlined', 'WeiboSquareOutlined', 'WeiboCircleOutlined', 'TaobaoCircleOutlined', 'Html5Outlined', 'WeiboOutlined', 'TwitterOutlined', 'WechatOutlined', 'YoutubeOutlined', 'AlipayCircleOutlined', 'TaobaoOutlined', 'SkypeOutlined', 'QqOutlined', 'MediumWorkmarkOutlined', 'GitlabOutlined', 'MediumOutlined', 'LinkedinOutlined', 'GooglePlusOutlined', 'DropboxOutlined', 'FacebookOutlined', 'CodepenOutlined', 'CodeSandboxOutlined', 'AmazonOutlined', 'GoogleOutlined', 'CodepenCircleOutlined', 'AlipayOutlined', 'AntDesignOutlined', 'AntCloudOutlined', 'AliyunOutlined', 'ZhihuOutlined', 'SlackOutlined', 'SlackSquareOutlined', 'BehanceOutlined', 'BehanceSquareOutlined', 'DribbbleOutlined', 'DribbbleSquareOutlined', 'InstagramOutlined', 'YuqueOutlined', 'AlibabaOutlined', 'YahooOutlined', 'RedditOutlined', 'SketchOutlined'] // 网站通用图标 const commonIcon = ['AccountBookOutlined', 'AimOutlined', 'AlertOutlined', 'ApartmentOutlined', 'ApiOutlined', 'AppstoreAddOutlined', 'AppstoreOutlined', 'AudioOutlined', 'AudioMutedOutlined', 'AuditOutlined', 'BankOutlined', 'BarcodeOutlined', 'BarsOutlined', 'BellOutlined', 'BlockOutlined', 'BookOutlined', 'BorderOutlined', 'BorderlessTableOutlined', 'BranchesOutlined', 'BugOutlined', 'BuildOutlined', 'BulbOutlined', 'CalculatorOutlined', 'CalendarOutlined', 'CameraOutlined', 'CarOutlined', 'CarryOutOutlined', 'CiCircleOutlined', 'CiOutlined', 'ClearOutlined', 'CloudDownloadOutlined', 'CloudOutlined', 'CloudServerOutlined', 'CloudSyncOutlined', 'CloudUploadOutlined', 'ClusterOutlined', 'CodeOutlined', 'CoffeeOutlined', 'CommentOutlined', 'CompassOutlined', 'CompressOutlined', 'ConsoleSqlOutlined', 'ContactsOutlined', 'ContainerOutlined', 'ControlOutlined', 'CopyrightCircleOutlined', 'CopyrightOutlined', 'CreditCardOutlined', 'CrownOutlined', 'CustomerServiceOutlined', 'DashboardOutlined', 'DatabaseOutlined', 'DeleteColumnOutlined', 'DeleteRowOutlined', 'DeliveredProcedureOutlined', 'DeploymentUnitOutlined', 'DesktopOutlined', 'DingtalkOutlined', 'DisconnectOutlined', 'DislikeOutlined', 'DollarCircleOutlined', 'DollarOutlined', 'DownloadOutlined', 'EllipsisOutlined', 'EnvironmentOutlined', 'EuroCircleOutlined', 'EuroOutlined', 'ExceptionOutlined', 'ExpandAltOutlined', 'ExpandOutlined', 'ExperimentOutlined', 'ExportOutlined', 'EyeOutlined', 'EyeInvisibleOutlined', 'FieldBinaryOutlined', 'FieldNumberOutlined', 'FieldStringOutlined', 'FieldTimeOutlined', 'FileAddOutlined', 'FileDoneOutlined', 'FileExcelOutlined', 'FileExclamationOutlined', 'FileOutlined', 'FileGifOutlined', 'FileImageOutlined', 'FileJpgOutlined', 'FileMarkdownOutlined', 'FilePdfOutlined', 'FilePptOutlined', 'FileProtectOutlined', 'FileSearchOutlined', 'FileSyncOutlined', 'FileTextOutlined', 'FileUnknownOutlined', 'FileWordOutlined', 'FileZipOutlined', 'FilterOutlined', 'FireOutlined', 'FlagOutlined', 'FolderAddOutlined', 'FolderOutlined', 'FolderOpenOutlined', 'FolderViewOutlined', 'ForkOutlined', 'FormatPainterOutlined', 'FrownOutlined', 'FunctionOutlined', 'FundProjectionScreenOutlined', 'FundViewOutlined', 'FunnelPlotOutlined', 'GatewayOutlined', 'GifOutlined', 'GiftOutlined', 'GlobalOutlined', 'HolderOutlined', 'HistoryOutlined', 'HeartOutlined', 'HddOutlined', 'GroupOutlined', 'GoldOutlined', 'HomeOutlined', 'HourglassOutlined', 'IdcardOutlined', 'ImportOutlined', 'InboxOutlined', 'InsertRowAboveOutlined', 'InsertRowBelowOutlined', 'InsertRowLeftOutlined', 'InsertRowRightOutlined', 'InsuranceOutlined', 'InteractionOutlined', 'KeyOutlined', 'LaptopOutlined', 'LayoutOutlined', 'LikeOutlined', 'LineOutlined', 'LinkOutlined', 'Loading3QuartersOutlined', 'LoadingOutlined', 'LockOutlined', 'MacCommandOutlined', 'MailOutlined', 'ManOutlined', 'MedicineBoxOutlined', 'MehOutlined', 'MenuOutlined', 'MergeCellsOutlined', 'MessageOutlined', 'MobileOutlined', 'MoneyCollectOutlined', 'MonitorOutlined', 'MoreOutlined', 'NodeCollapseOutlined', 'NodeExpandOutlined', 'NodeIndexOutlined', 'NotificationOutlined', 'NumberOutlined', 'OneToOneOutlined', 'PaperClipOutlined', 'PartitionOutlined', 'PayCircleOutlined', 'PercentageOutlined', 'PhoneOutlined', 'PictureOutlined', 'PlaySquareOutlined', 'PoundCircleOutlined', 'PoundOutlined', 'PoweroffOutlined', 'PrinterOutlined', 'ProfileOutlined', 'ProjectOutlined', 'PropertySafetyOutlined', 'PullRequestOutlined', 'PushpinOutlined', 'QrcodeOutlined', 'ReadOutlined', 'ReconciliationOutlined', 'RedEnvelopeOutlined', 'ReloadOutlined', 'RestOutlined', 'RobotOutlined', 'RocketOutlined', 'RotateLeftOutlined', 'RotateRightOutlined', 'SafetyCertificateOutlined', 'SafetyOutlined', 'SaveOutlined', 'ScanOutlined', 'ScheduleOutlined', 'SearchOutlined', 'SecurityScanOutlined', 'SelectOutlined', 'SendOutlined', 'SettingOutlined', 'ShakeOutlined', 'ShareAltOutlined', 'ShopOutlined', 'ShoppingCartOutlined', 'ShoppingOutlined', 'SisternodeOutlined', 'SkinOutlined', 'SmileOutlined', 'SolutionOutlined', 'SoundOutlined', 'TableOutlined', 'SyncOutlined', 'SwitcherOutlined', 'SubnodeOutlined', 'StarOutlined', 'SplitCellsOutlined', 'TabletOutlined', 'TagOutlined', 'TagsOutlined', 'TeamOutlined', 'ThunderboltOutlined', 'ToTopOutlined', 'TrophyOutlined', 'TranslationOutlined', 'TransactionOutlined', 'TrademarkOutlined', 'TrademarkCircleOutlined', 'ToolOutlined', 'UngroupOutlined', 'UnlockOutlined', 'UploadOutlined', 'UsbOutlined', 'UserAddOutlined', 'UserDeleteOutlined', 'VideoCameraAddOutlined', 'VerifiedOutlined', 'UsergroupDeleteOutlined', 'UsergroupAddOutlined', 'UserSwitchOutlined', 'UserOutlined', 'VideoCameraOutlined', 'WalletOutlined', 'WhatsAppOutlined', 'WifiOutlined', 'WomanOutlined'] // 全部图标 const allIcon = [...directionIcon, ...promptIcon, ...editIcon, ...dataIcon, ...brandIcon, ...commonIcon] // 初始化,加载所有图标 const direction = ref(directionIcon) const prompt = ref(promptIcon) const edit = ref(editIcon) const data = ref(dataIcon) const brand = ref(brandIcon) const common = ref(commonIcon) const all = ref(allIcon) // 加载所有图标 const setAll = () => { direction.value = directionIcon prompt.value = promptIcon edit.value = editIcon data.value = dataIcon brand.value = brandIcon common.value = commonIcon all.value = allIcon } // 图标类型Tab const typeTab = ref('all') const checkIcon = (icon: string) => { emit('update:modelValue', icon) pickerVisible.value = false } // 快速查询定位图标 const searchIcon = (value: string) => { if (value == '' || value == undefined || value == null) { setAll() } else { direction.value = directionIcon.filter(icon => icon.toLowerCase().includes(value.toLowerCase())) prompt.value = promptIcon.filter(icon => icon.toLowerCase().includes(value.toLowerCase())) edit.value = editIcon.filter(icon => icon.toLowerCase().includes(value.toLowerCase())) data.value = dataIcon.filter(icon => icon.toLowerCase().includes(value.toLowerCase())) brand.value = brandIcon.filter(icon => icon.toLowerCase().includes(value.toLowerCase())) common.value = commonIcon.filter(icon => icon.toLowerCase().includes(value.toLowerCase())) all.value = [...direction.value, ...prompt.value, ...edit.value, ...data.value, ...brand.value, ...common.value] } } // 打开图标选择器 const openPicker = () => { pickerVisible.value = true } </script> <style lang="less" scoped> .icon-picker { width: 280px; height: 35px; border: solid 1px #409eff; border-radius: 5px; background-color: rgb(64, 158, 255); cursor: pointer; transition: background-color 0.3s ease; color: rgb(255, 255, 255); display: flex; align-items: center; .icon-picker-icon-name { width: 75%; text-align: center; font-size: 14px; border-right: solid 1px rgb(235, 234, 234); } .icon-picker-icon { width: 25%; font-size: 25px; display: flex; align-items: center; justify-content: center; } } .icon-picker:hover { background-color: rgb(121, 187, 255); } .icon-picker-search { margin-bottom: 15px; } .icon-picker-tab { height: 50vh; overflow-y: auto; } .icon-content { display: flex; flex-wrap: wrap; gap: 10px; .icon-item { width: 65px; height: 60px; display: flex; align-items: center; justify-content: center; cursor: pointer; font-size: 35px; border-radius: 5px; transition: background-color 0.2s ease; border: solid 1px rgb(235, 235, 235); } .icon-item:hover { background-color: rgb(233, 233, 233); } } </style>
3. main.ts中全局注册IconPicker组件
// 导入图标选择器 import IconPicker from '@/components/IconPicker.vue' const app = createApp(App); // 全局注册图标选择器 app.component('IconPicker', IconPicker)
4. 表单中使用示例
<el-form-item label="导航图标:">
<icon-picker v-model="data.NAV_ICON"></icon-picker>
</el-form-item>
组件效果(未选择图标):

点击选择图标弹出选择器:可以分类/快速查找

点击图标选中效果:

效果还不赖= =

浙公网安备 33010602011771号