Vue3.5 企业级管理系统实战(五):图标组件
图标组件是前端开发中常用的元素,常见开发方式有三种:字体图标、SVG图标和图片图标。
字体图标:把图标当字体处理,每个图标对应字体字符。可通过设置字体属性控制显示,如 Font Awesome 库,引入 CSS 文件后即可使用。优点是易改大小、颜色且不失真,文件小加载快;缺点是只能单色,更新需重新生成字体文件。
SVG 图标:基于 XML 语法,可无损缩放、支持丰富效果。可内联 SVG 代码到 HTML,也能在前端框架封装成组件。优点是支持多色、无损缩放、可做动画交互;缺点是代码量大、旧版浏览器可能有兼容问题。
图片图标:将图标存为 PNG 等格式,用
<img>
标签或 CSSbackground - image
显示。优点是简单易用、兼容性好;缺点是不能无损缩放、文件大、难动态改颜色。
鉴于前文所述,本项目已完成支持图标的 UnoCSS 安装。UnoCSS 图标优势显著,灵活性高,支持按需引入,既能减小项目体积以加快加载速度,又能在运行时借助 CSS 类动态调整样式;集成便捷,以纯 CSS 实现,无额外 JavaScript 运行时负担,还能与 UnoCSS 原子化框架完美融合;视觉效果佳,基于 SVG 可无损缩放,且能呈现多色图标满足复杂设计;自定义能力强,允许用户添加自定义 SVG 图标并通过自定义 CSS 类打造独特风格。综合这些优点,我们决定采用 UnoCSS 开展图标配置工作。
采用 UnoCSS 配置图标,同时使用 Iconify 作为图标数据源。
1 安装插件
通过 pnpm 安装插件 @unocss/preset-icons 和 @iconify-json/ant-design
pnpm i @unocss/preset-icons @iconify-json/ant-design -D
@unocss/preset-icons
是 UnoCSS 的预设,用于在 UnoCSS 框架里集成图标支持。它支持多种图标源,借助简单的 CSS 类名,如i-{图标集前缀}-{图标名称}
,就能快速在项目中使用图标。还可自定义配置图标样式,如调整大小、颜色等。
@iconify-json/ant-design
是包含 Ant Design 图标集的 JSON 数据包。Ant Design 图标丰富美观,该包将图标以 JSON 格式管理。它能与 Iconify 无缝集成,方便在不同项目和框架中使用 Ant Design 图标。
在 uno.config.ts 中修改 uno 配置
//uno.config.ts
import { defineConfig } from "unocss";
import presetAttributify from "@unocss/preset-attributify";
import presetUno from "@unocss/preset-uno";
import transformDirective from "@unocss/transformer-directives";
// unocss图标预设会查找 依赖的图标库
// ant-design
import presetIcons from "@unocss/preset-icons";
export default defineConfig({
presets: [presetAttributify(), presetUno(), presetIcons()],
transformers: [transformDirective()], // apply
});
2 页面图标使用
去 Iconify 官网上,搜索我们安装的 ant-design 图标库,点击想要使用的图标,复制 Icon name (如 ant-design:account-book-filled)备用。
在页面中通过 i-{
Icon name} 即可使用,如下:
页面效果如下
3 图标原子类快捷方式
在使用 UnoCSS 集成图标时,若要为图标添加可复用样式,配置 UnoCSS 的 shortcuts
功能会是极为有效的解决方案。shortcuts
具备强大的自定义能力,支持用户定义原子化 CSS 类名的组合。用户只需创建一个涵盖图标样式相关原子类的快捷方式,后续在项目中就能直接调用该快捷类名,无需反复编写多个原子类,显著提升开发效率,让代码更加简洁易读。
比如,原本的写法如下,多个图标就要重复写多个同样的样式名称:
在 uno.config.ts 中配置 shortcuts: [["icon", "inline-block w-1em h-1em align-middle text-current"]],其中,icon
就是我们自定义的快捷类名,它将可复用的图标样式原子类组合到一起。
//uno.config.ts
import { defineConfig } from "unocss";
import presetAttributify from "@unocss/preset-attributify";
import presetUno from "@unocss/preset-uno";
import transformDirective from "@unocss/transformer-directives";
// unocss图标预设会查找 依赖的图标库
// ant-design
import presetIcons from "@unocss/preset-icons";
export default defineConfig({
presets: [presetAttributify(), presetUno(), presetIcons()],
transformers: [transformDirective()], // apply
shortcuts: [["icon", "inline-block w-1em h-1em align-middle text-current"]]
});
配置好后,可以在页面中使用快捷类名来定义统一的图标样式。
页面效果如下,F12可以看到样式已经添加上。
4 图标组件 svg-icon 封装
上文中的使用方式,如果我们想要使用其他图标资源,就需要手动下载相应的图标资源库,这样不仅容易造成文件冗余,使用过程繁琐,而且加载的图标还可能出现锯齿等显示问题。为解决这些痛点,实现以组件形式在 Vue 项目中渲染图标,可安装插件 @iconify/vue。@iconify/vue 是用于 Vue 项目集成 Iconify 图标功能的库,优势显著:
-
资源丰富调用统一:整合超 150 个图标集,像 Material Design Icons、Font Awesome、Ant Design Icons 等,超 20 万个图标,满足多样需求。且无论用哪个图标集,都能用统一语法引用,如
<Icon icon="mdi:home" />
,降低学习成本、提升开发效率。 -
渲染质量高:基于 SVG 渲染图标,相比传统图标字体,在任何尺寸下都清晰锐利,无模糊锯齿,视觉效果好。同时,因 SVG 支持多色,能轻松实现多色图标显示,满足复杂设计需求。
-
资源管理高效:支持按需加载,组件会根据实际使用情况,自动从 Iconify API 加载所需图标数据,无需打包所有图标,减小项目体积、加快页面加载。图标库更新时,也无需手动更新文件,组件自动获取最新数据。
-
框架集成性佳:专为 Vue 设计,与 Vue 生态无缝融合,可方便地在组件中使用。还能结合 Vue 响应式特性,实现动态图标切换。此外,支持与 Vue 样式绑定机制结合,动态改变图标大小、颜色、旋转等样式。
-
社区文档完善:Iconify 有活跃社区,开发者可分享经验、交流问题。同时提供详细文档与示例代码,初学者也能快速上手,降低使用门槛。
通过 pnpm 安装插件 @iconify/vue
pnpm i @iconify/vue
在 src 下新建文件夹 utils,新建文件 validate.ts,新增判断是否外部链接的方法
//validate.ts
//是否外部链接
export const isExternal = (path: string): boolean => {
return /https?/.test(path);
};
在 src/components 文件夹下新建 SvgIcon 文件夹,新建 index.vue 文件,封装图标组件如下:
//SvgIcon/index.vue
<template>
<IconifyIcon
:class="svgClass"
:icon="iconName"
v-if="!isExt"
v-bind="$attrs"
></IconifyIcon>
<div
v-else
:style="styleExternalIcon"
:class="svgClass"
bg-current
v-bind="$attrs"
></div>
</template>
<script setup lang="ts">
import { isExternal } from "@/utils/validate";
import { Icon as IconifyIcon } from "@iconify/vue";
const { iconName, customClass } = defineProps({
iconName: {
type: String,
default: ""
},
customClass: {
type: String,
default: ""
}
});
const isExt = computed(() => isExternal(iconName));
// class="customClass + icon"
// 组合成的类名
const svgClass = computed(() => (customClass ? `icon ${customClass}` : "icon"));
// 通过mask 渲染svg 图标 兼容性不好,可以通过请求svg的方式来渲染
const styleExternalIcon = computed(() => ({
mask: `url(${iconName}) no-repeat 50% 50%`,
"-webkit-mask": `url(${iconName}) no-repeat 50% 50%`,
"mask-size": "cover"
}));
</script>
<!-- 在实现图标的时候 尽量采用svg, 不要采用font图标,font图标放大时会出现锯齿等问题 -->
该图标组件主要功能是根据传入的图标名称动态渲染图标,支持使用 @iconify/vue
库渲染图标以及外部 svg 图标。该组件接收 iconName
和 customClass
两个属性。iconName
表示要渲染的图标名称,customClass
是可选的自定义类名。组件会根据 iconName
是否为外部链接来决定渲染方式:
-
若
iconName
不是外部链接,使用@iconify/vue
库中的IconifyIcon
组件来渲染图标,并应用svgClass
作为样式类,同时将其他未定义的属性透传。 -
若
iconName
是外部链接,渲染一个div
元素,通过mask
和-webkit-mask
CSS 属性使用外部 SVG 图标,同样应用svgClass
作为样式类,并透传其他属性。
5 svg-icon 组件使用
在页面中使用 svg-icon 组件,第一个组件使用本地图标,第二个组件使用外部 SVG 图标。
//Dashboard/index.vue
<template>
<div i-ant-design:account-book-filled icon></div>
<div i-ant-design:aim-outlined icon></div>
<svg-icon
icon-name="material-symbols-light:18-up-rating-outline-rounded"
></svg-icon>
<svg-icon
icon-name="https://zishui.oss-cn-beijing.aliyuncs.com/BugFilled.svg"
:custom-class="val"
@click="handle"
></svg-icon>
</template>
<script lang="ts" setup>
const { proxy } = getCurrentInstance()!;
const handle = () => {
proxy?.$message("This is a message.");
};
const val = ref("text-blue");
setTimeout(() => {
val.value = "text-red";
}, 1000);
</script>
页面效果如下,控制台可以看到渲染方式从之前的base64变成了svg形式。与 Base64 图标相比,svg 图标优势突出。视觉上,svg 基于矢量可无损缩放,在各分辨率设备都清晰,还能实现多色与复杂图形;Base64 缩放易失真。文件性能方面,svg 文件小,可被浏览器有效缓存,减少加载时间;Base64 编码后体积增加,缓存不便。开发维护上,svg 是文本格式,可直接编辑,便于复用和扩展;Base64 修改繁琐。另外,svg 中的文本利于 SEO,Base64 则无此优势。
以上,图标组件封装完毕。
下一篇将简单探讨Vue3中defineProps用法,敬请期待~