本文启发自于在项目“中国石油 - 云梦泽智慧平台 - 改版”项目缺陷记录
内容要实现的目标是:利用
fill: currentColor动态控制 svg 图片的颜色
fill: currentColor 是什么?
fill是 SVG 元素的一种属性,用于指定如何处理或者呈现元素的详细信息,比如:- ,对于形状元素和文本,它定义了绘制元素的颜色;
- 对于动画,它定义了动画的最终状态;
currentColor- 在 css 中,currentColor 是一个变量,这个变量的值是当前元素的 color 值;
- 如果当前元素没有在 CSS 里显示地指定一个 color 值,那它的颜色值就遵从 CSS 规则,从父元素继承而来;
以上内容截取自《fill:currentColor是什么意思?iconfont为何要设置 vertical-align: -0.15em?》
Vue3 中使用SVG作为图标
直接内联 SVG
将 SVG 代码直接嵌入 Vue 组件模板中,通过 CSS 控制样式
<template>
<div class="icon">
<!-- 通过 fill="currentColor" 继承 .icon 样式 color 属性颜色值 -->
<svg viewBox="0 0 24 24">
<path d="M12 2L2 7l10 5 10-5-10-5z" fill="currentColor" />
</svg>
</div>
</template>
<style scoped>
.icon {
color: #42b883;
}
</style>封装 SVG 为组件
将每个 SVG 封装成独立的 Vue 组件,便于复用
<!-- 封装图片组件 -->
<template>
<svg viewBox="0 0 24 24">
<path :fill="color" d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
</svg>
</template>
<script setup>
defineProps({ // 通过传值动态设置颜色,默认依旧取外层样式 color 颜色值
color: { type: String, default: 'currentColor' }
})
</script>
<!-- 父组件 -->
<template>
<IconHome color="#ff0000" />
</template>
<script setup>
import IconHome from '@/components/icons/IconHome.vue'
</script>以上内容截取自《Vue - Vue3 中使用SVG作为图标》
如果使用封装方法,每次都需要手动为图片创建组件,为了避免这种繁琐文中提到了
vite-svg-loader依赖
为什么选择 Vite SVG Loader?
在传统的 SVG 使用方式存在诸多不便:
- 手动复制粘贴 SVG 代码到组件中;
- 无法享受 Tree-shaking 优化;
- 缺少统一的优化和压缩机制;
Vite SVG Loader 解决了这些问题,让 SVG 图标管理变得简单高效!
安装
npm install vite-svg-loader --save-devvite.config.ts 配置
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import svgLoader from 'vite-svg-loader'
export default defineConfig({
plugins: [vue(), svgLoader()]
})直接作为 Vue 组件使用(默认)
<!-- 使用:必须手动 import 每个 SVG -->
<template>
<MyCustomIcon />
</template>
<script setup>
// 导入本地 SVG 作为组件
import MyCustomIcon from './icons/my-icon.svg'
</script>SVG 还可以通过 URL 、原始字符串 引入
// 作为URL导入
import iconUrl from './my-icon.svg?url'
// 作为原始字符串导入
import iconRaw from './my-icon.svg?raw'
// 明确指定为组件
import IconComponent from './my-icon.svg?component'以上内容截取自《Vite SVG Loader终极指南:高效管理SVG图标的10个实用技巧》
// 来自“豆包”的补充提示:
// v4 及以上版本将 defaultImport(默认导入格式)设置为 component,因此直接导入 SVG 就会自动转为组件无需加参数
// v3 及更早版本的 defaultImport 默认值是 url(返回 SVG 文件的 URL 字符串),因此要转组件必须显式加 ?component但此时会发现,每次都需要手动引入仍然略显繁琐,
unplugin-icons可以救赎这个问题
unplugin-icons
特性
- 🌏 通用性强
- ☁️ 按需加载 - 仅打包您实际使用的图标,同时保留所有可用选项。
- 🖨 支持 SSR / SSG - 图标随页面一同加载,告别未样式化内容闪烁(FOUC)。
- 🌈 可自定义样式 - 像使用样式和类一样轻松更改图标大小、颜色,甚至添加动画效果。
- 📥 自定义图标 - 加载您的自定义图标,轻松实现通用集成。
- 📲 自动导入 - 直接在模板中以组件形式使用图标。
- 🦾 TypeScript 支持。
- 🔍 浏览图标
安装
npm i -D unplugin-icons安装图标数据
<!-- 安装单个图标集 -->
npm i -D @iconify-json/mdi @iconify-json/carbon
<!-- 安装完整集合(所有图标集约 120MB) -->
npm i -D @iconify/json自动导入
npm i unplugin-vue-components -Dvite.config.ts 配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import IconsResolver from 'unplugin-icons/resolver'
import Icons from 'unplugin-icons/vite'
import Components from 'unplugin-vue-components/vite' // 图标自动导入
export default defineConfig({
plugins: [
vue(),
// 1. 配置 unplugin-icons
Icons({
compiler: 'vue3', // 明确编译为 Vue3 组件(必填)
autoInstall: true, // 自动安装缺失的图标集(可选,推荐)
scale: 1, // 图标默认缩放比例(可选,默认 1)
defaultClass: '', // 应用到所有图标的默认类名(可选)
defaultStyle: '', // 应用到所有图标的默认样式(可选)
jsx: 'react', // JSX framework: 'react' or 'preact' (when compiler: 'jsx')
iconCustomizer: (collection, icon, props) => { // 为每个图标添加自定义样式
if (collection === 'mdi' && icon === 'account') {
props.width = '2em'
props.height = '2em'
}
},
transform: (collection, icon, props) => { // 在加载期间对所有自定义图标应用转换
if (collection === 'my-icons' && icon === 'account') {
return svg.replace(/^<svg /, '<svg fill="currentColor" ')
}
return svg
},
customCollections: {}, // 加载您自己的自定义图标,并使用相同的通用 API 来使用它们
}),
// 2. 配置 unplugin-vue-components(实现图标自动导入)
Components({
resolvers: [
// 自动导入图标组件(核心)
IconsResolver({
// 组件命名模式 {prefix}-{collection}-{icon}
// prefix:组件名称前缀(默认值:i)
// collection:Iconify 集合 ID(例如:mdi、carbon、fa-solid)
// icon:图标名称(短横线连接格式)
prefix: 'icon', // 修改图标组件前缀,比如 <icon-ant-design-home />
// enabledCollections: ['ant-design-icons', 'mdi'], // 只启用指定图标集(可选)
alias: { // 较长的图标集名称创建更短的别名
// <icon-icon-park-abnormal /> 使用原组件名引入
// <icon-park-abnormal /> 使用别名引入
park: 'icon-park',
fas: 'fa-solid',
}
}),
],
}),
],
})自定义集合加载器加载多种图标源
unplugin-icons 的 customCollections 自定义集合加载器允许你从多种来源加载图标:
- 本地文件系统 - 直接读取项目中的 SVG 文件
- 外部包 - 使用第三方图标包
- 远程 API - 从网络服务获取图标数据
文件系统图标加载器配置方法
使用 FileSystemIconLoader 可以快速设置本地图标库:
import { FileSystemIconLoader } from 'unplugin-icons/loaders'
Icons({
customCollections: {
// 键名为自定义图标集名称(分组名)
// FileSystemIconLoader 是批量加载指定目录下的所有 SVG 文件
'my-icons': FileSystemIconLoader(
// 参数1:SVG 文件所在的目录(必填,绝对/相对路径均可)
'./assets/icons',
// 参数2(可选):自定义图标名的处理函数(默认取 SVG 文件名)
(svgFileName) => {
// 比如去掉文件名前缀:icon-user.svg → user
return svgFileName.replace(/^icon-/, '')
}
)
}
})种配置会自动扫描指定目录下的所有 SVG 文件,并将其转换为可用的图标组件
远程 API 图标加载实战
对于需要从远程服务获取图标的场景,你可以这样配置:
Icons({
customCollections: {
'remote-icons': async (iconName) => {
return await fetch(`https://api.example.com/icons/${iconName}.svg`)
.then(res => res.text())
}
}
})外部包集成技巧
unplugin-icons 支持通过 ExternalPackageIconLoader 加载第三方图标包:
import { ExternalPackageIconLoader } from 'unplugin-icons/loaders'
Icons({
customCollections: ExternalPackageIconLoader('my-awesome-collection')
})基本用法(非自动导入)
使用 ~icons/{图标集}/{图标名} 约定导入图标,并将它们用作组件
import IconAccessibility from '~icons/carbon/accessibility'
import IconAccountBox from '~icons/mdi/account-box'
<template>
<icon-accessibility/>
<icon-account-box style="font-size: 2em; color: red"/>
</template>以上内容截取自
