Vue 中 SVG 进阶使用

本文启发自于在项目“中国石油 - 云梦泽智慧平台 - 改版”项目缺陷记录

内容要实现的目标是:利用 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-dev

vite.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

特性

  • 🌏 通用性强
    • 🤹 任意图标集 - 约 150 个热门图标集,包含超过 200,000 个图标、徽标、表情符号等。由 Iconify 提供支持。
    • 📦 主流构建工具 - Vite、Webpack、Rollup、Nuxt、Rspack 等。由 unplugin 提供支持。
    • 🚀 主流框架 - Vanilla、Web Components、React、Vue 3、Solid、Svelte 等。贡献代码
    • 🍱 以上任意组合!
  • ☁️ 按需加载 - 仅打包您实际使用的图标,同时保留所有可用选项。
  • 🖨 支持 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 -D

vite.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-iconscustomCollections 自定义集合加载器允许你从多种来源加载图标:

  • 本地文件系统 - 直接读取项目中的 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>

以上内容截取自

unplugin-icons

unplugin-icons自定义集合加载器:从文件系统到远程API的终极指南

unplugin-icons 配置完全手册:从基础设置到高级定制

分类: 工作相关

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注