ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Vue图标库选型与接入指南:免费方案、按需加载与避坑实践

Vue图标库选型与接入指南:免费方案、按需加载与避坑实践 做 Vue 项目这么多年图标库是我每次新建项目时第一个纠结的东西。组件库自带的图标不够用网上下载的 PNG 放大了就糊字体图标又经常出现显示不出来的问题。后来把免费 Vue 图标库挨个试了一遍踩了不少坑也理清了一些思路。这篇就把我实测下来觉得好用的几个免费方案以及在不同场景下的选型建议、接入流程、打包时容易踩的坑都整理出来。不管你是刚入门还是已经在做中大型项目都可以直接拿去对照参考。1. 先聊聊免费 Vue 图标库这件事1.1 为什么图标库要单独讲直接复制图片不香吗很多朋友最开始做界面的时候习惯直接去图标网站下载 PNG 文件然后放到工程的 assets 目录里引用。这种方式在个人练习项目里没问题一旦进入正式项目几个麻烦就出现了第一图片体积不可控。一张 48px 的 PNG 图标通常能压到 1-2KB但如果在高 DPI 屏幕上要显示 2 倍图、3 倍图就得同时维护多张尺寸文件一个功能页面用上几十个图标资源体积很快就会涨上去。第二颜色和尺寸会变得很难统一。不同设计师导出的图标规格不一致你在代码里要么一张张去改要么被迫用object-fit和background-size去硬适配效果还不一定好。第三如果产品后期需要换主题色或者做暗黑模式PNG 图片根本没法跟随文字颜色一起变化只能重新导图。相比之下使用 Vue 图标库的核心优势在于图标以 SVG 内联或者字体形式存在可以通过 CSS 控制颜色、字号、加粗、动画还能在打包时按需加载体积和灵活性都远超图片方案。而且好的图标库通常提供统一的视觉规范整个应用的图标风格保持一致性这一点在多人协作项目里尤其重要。1.2 选图标库前先搞懂三件事图标格式、渲染方式和样式体系在具体选库之前有几个基础概念最好先弄清楚不然很容易被各种库的文档绕晕。首先是 SVG 图标。SVG 本身就是一种矢量图片格式可以内联在 HTML 里也可以作为独立文件引用。SVG 图标的优点是清晰度极高、颜色可控、支持 CSS 动画缺点是如果每个图标单独引入浏览器要发起多次请求。所以现代的图标库通常会把多个 SVG 合并成雪碧图Sprite或者直接封装成 Vue 组件用.vue文件把每个图标定义成一段可复用的 SVG 模板。渲染时组件会直接输出路径信息不需要额外加载图片资源。其次是字体图标。字体图标的原理是把每个图标映射到一个 Unicode 字符上然后通过自定义字体文件渲染。典型代表就是 Font Awesome。这种方式最大的好处是渲染极快、兼容老浏览器可以通过font-size和color直接控制大小和颜色。但它有一个明显的缺点图标颜色只能是单色除非用 CSS 多背景技巧做复杂渐变成本很高而且字体文件哪怕只用了一个图标也要把整个字体文件加载进来没法真正做到按需打包。最后要说的是样式体系。每个图标库都有自己的线条粗细、圆角风格、填充方式。比如 Linear 风格、Filled 风格、Outlined 风格混用不同体系的图标会显得页面很“花”。所以不管选哪个库尽量让一个项目里面统一使用同一套风格的图标这是我在实际项目里看着最舒服的做法。2. 我实测常用的几个免费 Vue 图标库2.1 Element Plus Icons如果你正好在用 Element Plus如果你项目里已经安装了 Element Plus那element-plus/icons-vue基本就是最省事的选择。这个包就是 Element Plus 官方维护的图标集合风格和 Element Plus 组件完全统一而且全部以 Vue 组件形式提供。安装非常简单npm install element-plus/icons-vue然后在main.js里可以按需注册也可以全局注册。我最推荐的做法是在组件里按需引入因为这样能配合打包工具的 tree-shaking把没用到的那部分图标从最终包里删掉。template el-iconEdit //el-icon /template script setup import { Edit } from element-plus/icons-vue /script这里要注意Element Plus 的el-icon组件会给内部 SVG 自动继承当前的文字颜色和字号。如果你不用el-icon包裹直接渲染Edit /图标会默认使用自身路径里写的颜色可能和页面风格对不上。2.2 Iconify一套接口吃下所有图标集如果说只能推荐一个图标方案我会推荐 Iconify。它不是某一个具体的图标风格而是一个图标聚合平台里面的图标集数量超过 100 套包括我们熟悉的 Font Awesome、Material Design Icons、Tabler Icons、Remix Icon 等都可以通过它统一引用。Iconify 提供了几种用法一种是直接引入它的 Web 版本运行时从 CDN 加载图标数据另一种是用iconify/vue这个 Vue 组件在渲染时动态解析图标名称。同时它也支持编译期按需引入配合unplugin-icons插件使用性能和本地 SVG 组件基本没区别。实际使用中最吸引我的是这种动态图标能力。比如后端接口返回一个图标名称mdi:home页面只需要写template Icon iconmdi:home / /template script setup import { Icon } from iconify/vue /script图标就能自动渲染出来。这在低代码平台、配置化后台系统里非常实用因为你不需要事先知道用户会用到哪个图标。2.3 unplugin-icons Vite按需加载的终极方案如果你用 Vite 构建 Vue 项目我强烈建议直接上unplugin-icons。这个插件的思路是在编译阶段把图标名转换成对应的 SVG 代码打包进组件里做到真正的按需加载。它支持几十个流行图标库也可以使用本地自定义的.svg文件。安装方式如下npm install -D unplugin-icons然后在vite.config.js里配置import Icons from unplugin-icons/vite export default { plugins: [ Vue(), Icons({ compiler: vue3, autoInstall: true }) ] }配置之后你可以像下面这样直接使用图标组件template i-mdi-home / i-carbon-user / /templateunplugin-icons生成的组件名规则是i-集合名-图标名比如mdi:home就会对应i-mdi-home /。因为编译时就把图标内容变成了组件代码所以最终构建产物里只包含你真正用到的图标首屏加载体积会明显下降。我之前把项目里的 Font Awesome 字体图标全部替换成 unplugin-icons 之后打包体积从大约 1.2MB 降到了 900KB这还是在用了不少图标的情况下。如果你页面图标少收益会更明显。2.4 其他值得留名的免费图标库除了上面三个还有几个免费图标库在实际项目中也很常见。Font Awesome Free 是一个老牌图标库免费版图标数量也够用。它既提供 CSS 字体方案也有 SVG 组件版本。但要注意Font Awesome Free 的图标风格比较重棱角明显和很多现代简洁 UI 放在一起会有点突兀。如果你使用它的 React/Vue 组件版本要注意fortawesome/free-solid-svg-icons等包是按风格拆分的需要分开安装。Remix Icon 是一套非常精致的线性图标风格偏现代适合做管理后台。它提供了官方的 React 和 Vue 组件库还有一个很实用的特性每个图标都同时有线条版和填充版命名上用line和fill区分。Tabler Icons 是另一套我很喜欢的线性图标线条更细风格更轻。它的免费使用条件很宽松可以商用也支持自定义修改。如果你想要一套比较统一的线性风格图标集Tabler Icons 值得优先考虑。Heroicons 是 Tailwind CSS 作者发布的图标库风格圆润、简洁也同时提供 outlined 和 solid 两套。虽然最初是给 Tailwind 用的但也直接提供了 Vue 组件版本可以单独在 Vue 项目里用。这些库的共通点都是以 SVG 为基础都有对应的 Vue 组件封装接入成本很低。你完全可以根据项目视觉风格来挑选一套主图标库再配合 Iconify 应付偶尔需要补充的图标。3. Vue 项目里接入图标库的完整实操流程3.1 从创建 Vue 项目到安装依赖先说明一下我这里用 Vue 3 Vite 作为例子。如果你还在用 Vue 2 Webpack思路是一样的只是个别插件配置略有不同。新建项目可以用官方推荐的命令npm create vuelatest这个命令会创建一个基于 Vite 的 Vue 3 项目过程中可以选择是否安装 TypeScript、Router、Pinia 等。如果你只是想快速测试图标库也可以选择创建一个最小化的项目。创建完项目后安装图标库依赖。以我常用的组合为例同时安装unplugin-icons和一个图标集npm install -D unplugin-icons npm install -D iconify/jsoniconify/json是 Iconify 的本地图标数据包装完之后unplugin-icons就能离线解析所有 Iconify 支持的图标不需要请求外部网络。这个包体积比较大因为它包含了所有图标集的数据但你不用担心它只是在编译期使用不会全部打进业务代码里。如果你只想用某一个特定图标库比如 Tabler Icons也可以单独安装对应的图标包npm install -D tabler/icons-vue然后用组件方式直接引用template IconHome / /template script setup import { IconHome } from tabler/icons-vue /script3.2 全局注册、按需引入和组件封装图标库接入方式通常有全局注册和按需引入两类。全局注册的好处是模板里直接用不用每个组件都 import 一遍坏处是如果注册方式不对很容易把整个图标库全量打进包里。如果你用 Element Plus Icons官方推荐的做法是在main.js里遍历注册import { createApp } from vue import App from ./App.vue import * as ElementPlusIconsVue from element-plus/icons-vue const app createApp(App) for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component) } app.mount(#app)这段代码看起来方便但如果你不在意按需加载它会把这个包里面所有图标都注册成全局组件。虽然 Vue 组件只是在注册阶段创建了组件定义没有实际渲染时不会生成太多 DOM但组件定义本身还是有内存占用而且会让项目的全局组件数量特别多不利于维护。更好的做法是按需引入然后封装一个公共组件。比如创建一个AppIcon.vuetemplate component :isiconComponent / /template script setup import { computed } from vue import * as ElementPlusIconsVue from element-plus/icons-vue const props defineProps({ name: { type: String, required: true } }) const iconComponent computed(() { return ElementPlusIconsVue[props.name] }) /script这样在业务组件里只需要AppIcon nameEdit /使用起来很方便而且因为name是运行时传入的字符串上面这种写法会把整个图标库的组件都引用进来所以只适合图标数量有限的场景。如果你非常在意打包体积还是应该在模板里显式引用某个图标组件让打包工具可以做 tree-shaking。3.3 动态图标和远程图标的实现思路很多后台项目会遇到一个需求菜单图标是由后台配置的前端拿到图标名称后要动态渲染。这时候有两种方案可以选。第一种方案是维护一个图标映射表把所有可能用到的图标都注册到一个对象里import { Home, User, Setting } from element-plus/icons-vue export const iconMap { Home, User, Setting }然后在动态组件里直接取template component :isiconMap[iconName] / /template这种方案的好处是安全、可控你只允许后台传指定的图标名。坏处是新增图标时需要改前端代码而且如果后台传来的名称拼错了界面会很安静地什么都不显示。第二种方案是用 Iconify 的运行时解析能力。iconify/vue的Icon组件接收一个字符串图标名然后自己去加载对应的 SVG 数据。如果你从 CDN 加载它就能实时访问到最新加入的图标不需要重新发布前端。template Icon :icon${prefix}:${name} / /template这种方案灵活很多适合做低代码平台但我建议你在使用前考虑一下网络依赖。如果业务系统部署在内网环境或者很在乎首屏加载速度最好还是把需要用到的图标集提前下载下来用离线模式解析。4. 使用过程中常踩的坑和排查技巧4.1 打包后图标显示异常的几种情况图标在开发环境一切正常打包上线后却变成空白、乱码、或者出现一个方框这是很多人遇到过的头疼问题。根据我的经验绝大多数情况是下面几个原因。第一个原因是字体图标的字体文件路径不对。以 Font Awesome 的 CSS 方案为例构建后的 CSS 文件里url()路径是相对路径如果你的静态资源部署在子路径下比如 CDN 的https://cdn.example.com/static/字体文件可能就找不到了。解决办法是在构建配置里正确设置base或者publicPath。第二个原因是 SVG 雪碧图加载失败。有些插件会把所有 SVG 合并成一个.svg文件然后通过use href#icon-id引用如果这个雪碧图文件没有正确输出到静态目录或者跨域被浏览器拦截图标就会白屏。排查时可以先打开开发者工具看 Network 里有没有sprite.svg相关的请求是红色失败的。第三个原因是 CSS 样式覆盖。有些图标库的样式名很通用比如.icon如果你自己在项目中写了.icon { fill: ... }之类的全局样式可能会把图标的颜色或者尺寸改掉。建议在调试前先检查一遍全局样式特别是 reset 样式和 antd/element 这类组件库的样式。4.2 tree-shaking 没生效包体越来越大很多图标库都说自己支持按需加载但如果你用错了引入方式tree-shaking 不会生效。最常见的错误是从一个统一入口导入所有图标比如import * as Icons from some-icons这种方式会把整个模块引入进来打包工具很难判断哪些属性没被用到。正确的做法是从具体的子路径导入比如import { Home } from some-icons或者使用插件生成的单个组件。比如unplugin-icons的方案每个图标都是一个独立的虚拟模块天然支持按需加载。另外如果你的项目里直接用iconify/vue的运行时模式其实是动态加载图标的不存在打包体积的问题但在线加载会有额外的网络请求。你需要权衡一下是更在乎构建体积还是更在乎运行时依赖。我自己的选择标准是如果项目中用到的图标数量比较多且相对固定就用 unplugin-icons 的本地编译方式如果图标数量少而且固定不变直接引入对应图标组件如果图标数量会动态变化才考虑运行时 Iconify 方案。4.3 图标库版本和 Vue 版本不匹配怎么办Vue 2 和 Vue 3 的组件 API 差异很大所以很多图标库也都分别发布了针对不同版本的包。比如 Element Plus Icons 的包名是element-plus/icons-vue它只支持 Vue 3如果你的项目是 Vue 2 Element UI那需要用的是另一个老包vue-fontawesome或者自己封装 SVG 组件。Iconify 也分成了iconify/vueVue 3和iconify/vue2两个版本安装时千万不要装错。装错之后通常的表现是页面报错提示组件没有注册或者控制台出现 “Failed to resolve component: Icon” 这样的警告。还有一个常见坑是组件库本身的版本和图标库版本不匹配。比如 Element Plus 在升级到 2.x 的某个小版本后图标包也要求同步更新否则图标组件的样式会异常。遇到这种情况最简单的处理是锁定版本号不要用^范围导致自动升级到不兼容版本。如果你在开发自用组件库建议把图标组件单独抽成一个依赖不要和主组件库绑定太深。这样即使主组件库升级图标部分依然可以独立演进。5. 给不同项目阶段的使用建议与心得5.1 小项目、大项目、低代码平台分别怎么选针对不同规模的项目我的选型建议略有不同。如果是个人练习项目或者快速原型建议直接用你正在使用的 UI 组件库自带图标比如 Element Plus Icons、Vant Icons、Naive UI 的 icons。这些图标在视觉上跟组件库天然统一接入成本几乎为零不需要额外配置插件。缺点是图标数量有限遇到特殊场景可能找不到合适的图标。如果是正式业务系统尤其是后台管理系统我建议用 Iconify 配合 unplugin-icons。这样做的好处是图标集中选择面广既可以保持整体风格统一又能灵活选取多个不同风格的图标编译时按需加载构建产物很小后续要换图标风格也相对容易只需要批量替换图标名称。如果是在做低代码平台或者配置化系统需要支持用户自定义图标那就离不开运行时动态图标。这时候可以基于iconify/vue做一个图标选择器组件从 Iconify 的默认集里选也支持用户上传自定义 SVG然后统一转换成一个可被系统识别的业务编码。这样配置后台只需要存字符串前端渲染时再解析成图标。5.2 我的个人经验和最后一点小建议踩过这么多坑之后我现在新建项目时会坚持几条原则。第一不要一个项目里混用多套图标库。图标风格不一致会让整个界面显得杂乱而且多套方案意味着多份体积、多处配置、多组样式。如果你确确实实需要一个特殊图标当前主图标库没有我建议去 Iconify 的集合里找一个相近的而不是另装一个库。这样至少可以统一通过 Iconify 加载路径来管理。第二尽量封装一层公共图标组件不要直接在业务代码里到处 import 具体图标。我的习惯是做一个BaseIcon.vue内部通过 name 属性映射到具体库再通过 size、color、strokeWidth 等 props 统一控制样式。这样以后就算把图标库换掉也只改这个公共组件业务代码基本不动。第三重视图标命名的可读性。图标名称是你项目中很重要的“代码注释”比如IconHome、IconUserAvatar、IconSaveSuccess这样的名称比Icon1、Icon2要清晰得多。在团队协作时统一命名规则也能减少沟通成本。第四定期检查图标使用情况。即使 tree-shaking 做得好一个长期维护的项目里也很难避免出现“代码里引用了某个图标但后来功能删了图标忘了删”的情况。可以用一些代码扫描工具或者在实际测试时检查一下生产环境里有没有发出意外的图标相关请求。第五留意开源图标库的许可证。虽然我上面推荐的都是免费可商用的库但每个库的具体协议还是有点差别有的要求署名有的则完全无限制。商用之前建议去对应仓库看一眼 LICENSE 文件不要到后期被法务找上门再后悔。我在实际项目中目前用得最多的是unplugin-icons iconify/json的组合配合一个封装好的基础图标组件几乎能覆盖所有日常开发需求。如果你也想省心一点可以直接照这个方案去搭然后再根据项目风格微调选用的图标集。
返回列表