{T}

图标资源接入与复制能力

概述

图标往往是组件库最先遇到的"基础设施"。本文讲图标体系的第一步——统一资源来源与接入策略,并落地三条主线:Iconify(主入口)、自定义 SVG 组件、IconFont 字体图标,最后用 Clipboard API 给图标列表加上一键复制能力,提升文档与设计协作效率。

学习目标

  • 理解"先统一来源与接入策略,再封装组件"的图标体系设计顺序
  • 掌握 Iconify 的按需加载、预加载与本地化 Provider 配置
  • 能用 vite-plugin-svg-icons + 统一 SvgIcon 组件接入自定义 SVG
  • 了解 IconFont 集成方式,以及三类图标方案的选型对比
  • 用 Clipboard API 为图标列表实现复制名称 / SVG 的能力

一、先统一来源与接入策略

图标来源若不统一,很快会出现命名混乱、风格不一致、调用方式分裂。常见来源有三类:

  • Iconify:150,000+ 图标、100+ 图标集,统一 API、按需加载,适合作为前期主入口。
  • 自定义 SVG:业务专用或品牌图标,Iconify 覆盖不到时使用。
  • IconFont:设计师在 iconfont.cn 上传的字体图标。

无论来源如何,最终都应收口到同一个图标组件,调用方式、命名约定、渲染入口三件事尽早固定。

二、Iconify:丰富、按需、统一

Iconify 用 前缀:图标名(如 ep:editmdi:home)统一调用,配合 UnoCSS 可直接 <div class="i-ep-edit" />。它最大的价值是"图标丰富 + 按需加载 + 调用统一",适合通用图标;业务特殊图标仍需自定义 SVG。

两个高频优化点:

  1. 预加载解决闪烁:默认从 CDN 异步加载会导致图标短暂闪烁,用 loadIconsonBeforeMount 预加载核心图标列表,加载后进入内存缓存。
  2. 本地化去 CDN:内网 / 离线项目用 addAPIProvider('local', { resources: [...] }) 把图标 JSON 放到 public/icons 下,改用 @local:bi:home 形式访问,不再依赖网络。

缓存层级上,Iconify 有内存缓存(最快)、LocalStorage(跨页持久)、Service Worker(PWA 离线)三层,首次走网络、之后命中缓存。

三、自定义 SVG 组件

固定品牌或业务图标更适合本地 SVG。用 vite-plugin-svg-iconssrc/assets/icons 下的 .svg 自动注册成 SVG Sprite,配合统一组件 SvgIcon 提供一致的 type / size / color API:

Vue SFC
<template>
  <svg :style="{ width: `${size}px`, height: `${size}px` }" aria-hidden="true">
    <use :xlink:href="`#icon-${type}`" :fill="color" />
  </svg>
</template>

<script setup lang="ts">
const props = defineProps({
  type: { type: String, required: true },
  size: { type: [Number, String], default: 16 },
  color: { type: String, default: 'currentColor' }
})
</script>

关键点:SVG 文件用 currentColor 而非硬编码颜色,使图标跟随文字颜色;main.ts 需导入 virtual:svg-icons-register 虚拟模块。注意该插件在处理 stroke 图标时偶有变形,优先选 fill 图标或用社区修复版。

四、IconFont 集成

IconFont 是 iconfont.cn 提供的字体图标方案,支持 Unicode / Font Class / Symbol 三种引用。把设计师图标接入时,同样包装进统一组件(如 IconFonticonfont icon-${type} 类名),避免与 Iconify、自定义 SVG 三套写法并存。缺点是字体 URL 易硬编码、难本地化,适合已有 iconfont 项目资产的场景。

五、图标复制能力

当图标很多时,复制名称、类名或 SVG 代码能显著降低使用门槛。核心是 navigator.clipboard.writeText

ts
const copyIcon = async (text: string) => {
  await navigator.clipboard.writeText(text)
}

复制内容应与真实使用方式一致(如 ep:edit 或完整 <svg> 片段),并为成功 / 失败提供反馈。图标展示项与复制按钮组合后,可直接服务文档页或图标选择器。

六、选型对比

维度Iconify自定义 SVGIconFont
图标数量15 万+自定义设计师上传
网络依赖CDN 模式需要字体文件
自定义难度较困难容易中等
推荐场景图标变化多、需大量选择图标固定、品牌图标已有 iconfont 资产

经验策略:项目初期图标未定、需大量选择时用 Iconify;图标已固定或需品牌定制用自定义 SVG;已有 iconfont 项目资产时直接集成。

七、图标资源的工程化收尾

接入之后还有几件收尾工作容易被忽略,它们决定图标体系是"能用"还是"可交付"。

  • 图标集数据固化:把某个图标集的可用名列表沉淀成 ep.json(含 collectionicons 数组),既作为列表组件数据源,也便于统计体积与做按需加载。
  • SVG 优化:设计师导出的 SVG 常含冗余节点、注释与硬编码尺寸,用 svgomg 等工具压缩,并统一成 viewBox + currentColor 的干净结构,避免颜色被锁死。
  • 按需与体积边界:Iconify 默认按需已足够;自定义 SVG 则要警惕把所有图标打进首屏——只在真正用到的入口注册 Sprite。
  • 文档站呈现:把搜索、复制、预览三件事合到图标页,使用者"看到就能拿走",这才体现图标体系的协作价值。
  • 类型与本地化:若直接 import ep.json,需在 env.d.ts 补全 JSON 模块声明;内网场景则把本地图标源放到 public 以摆脱 CDN 依赖。

把这些收尾标准化,图标体系就从零散技巧变成可维护的基础设施。

八、命名约定:让三类来源收敛到同一套词表

来源再多,调用端只认一套命名,混乱才不会发生。推荐四条收敛规则:

  • 统一前缀语义:Iconify 用 collection:name,自定义 SVG 用 icon- 前缀,IconFont 用 iconfont icon- 前缀,三者泾渭分明,不混写。
  • 业务图标走 kebab-case:如 export-orderuser-avatar,避免中文或驼峰,方便在属性里直接书写与搜索。
  • 文档站与代码同源:图标页展示的名字就是组件调用名,不让使用者做二次翻译。
  • 弃用要有去处:下线图标时同步从 ep.json 与文档页移除,避免"文档有、代码无"的幽灵引用。

命名约定看似小事,却是图标体系能否长期不腐化的底层纪律——它让三类来源在调用层彻底收敛成一套词表。

常见问题

问题原因解决方案
图标闪烁异步从 CDN 加载loadIcons 预加载
本地图标加载失败JSON 路径或 Provider 配置错核对 public 路径与 addAPIProvider
SVG 颜色不变文件硬编码颜色改用 currentColor 或组件 color
stroke 图标变形插件已知问题用修复版或避免 stroke 图标
复制无效非 HTTPS / 非 localhost在 localhost 或 HTTPS 下测试

延伸阅读