vue 项目svg导入的多种方案优缺点分析

SVG(Scalable Vector Graphics,可缩放矢量图形)是一种基于可扩展标记语言(XML)的图形格式,用于描述二维矢量图形。它由W3C制定,是一个开放标准。

SVG概述

  • SVG允许3种图形物件类型:矢量图形、栅格图像以及文本。
  • SVG提供的功能集涵盖了嵌套转换、裁剪路径、Alpha通道、滤镜效果、模板对象以及可扩展性。
  • SVG严格遵从XML语法,并用文本格式的描述性语言来描述图像内容,因此是一种和图像分辨率无关的矢量图形格式。

SVG的优点: 1.矢量图形缩放不会失真(像素点数量不变而导致图像出现模糊、锯齿等),而光栅图形(PNG、JPG)缩放会导致失真。

  • 矢量图形:基于矢量的点、线、形状和数学公式来构建的图形,该图形是没有像素的,放大缩小不会失真。
  • 光栅图形:由像素点构建的图像---微小的彩色方块,大量像素点可以形成高清图像,比如照片。图像像素越多,质量越高。
  1. SVG 与 JPEG 和 GIF 图像比起来,尺寸更小,且可压缩性更强。

  2. SVG图像中的文本是可选的,同时也是可搜索的,且可以与 JavaScript 技术一起运行

SVG的缺点

  1. SVG复杂度越高渲染速度就会越慢(任何过度使用DOM的应用都不快)

  2. SVG不适合游戏应用,只能结合Canvas来实现

  3. SVG不能动态的修改动画内容

使用

在网页中使用SVG有多种方法。以下是一些常见的方法:

  1. 直接嵌入HTML中:你可以直接将SVG代码嵌入到HTML文档中。这种方法允许你使用CSS和JavaScript直接与SVG元素交互。
html 复制代码
<svg width="100" height="100">
		<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>
  1. 使用<img>标签 :如果你有一个.svg文件,你可以像使用其他图像格式一样使用它。
html 复制代码
<img src="path/to/your/image.svg" alt="Description of SVG">
  1. 使用CSS背景:SVG也可以作为CSS背景图像使用。
css 复制代码
.svg-background {
		background-image: url('path/to/your/image.svg');
}
  1. 使用<object><embed>标签:这两种方法允许你嵌入外部SVG文件,并保持文件的交互性。
html 复制代码
<object data="path/to/your/image.svg" type="image/svg+xml"></object>

html 复制代码
<embed src="path/to/your/image.svg" type="image/svg+xml">
  1. 使用<iframe> :你可以在<iframe>中加载SVG文件。
html 复制代码
<iframe src="path/to/your/image.svg"></iframe>
  1. 使用JavaScript:你可以使用JavaScript动态地创建SVG元素并添加到DOM中。

在vite 中使用 svg 插件

使用svg 插件这部分,有两个比较有名的插件 分别是unplugin-iconsvite-plugin-svg-icons 都是用于处理 SVG 图标的 Vite 插件,但它们有一些不同的特点和用途。

unplugin-icons

  1. 功能丰富 :除了支持本地 SVG 图标,它还支持 iconify 图标库,这意味着你可以直接从数千个图标中选择并按需导入。

  2. 按需导入:只有在代码中实际使用的图标才会被包含在最终的构建中,这有助于减少最终的包大小。

  3. 自动组件化:它可以自动将图标转换为 Vue 或 React 组件,使得在组件中使用图标变得非常简单。

  4. 扩展性:支持自定义加载器和解析器,这意味着你可以扩展它以支持其他图标库或格式。

  5. 与其他 unplugin 插件集成 :例如, unplugin-auto-import 集成,可以自动导入和注册图标组件。

vite-plugin-svg-icons

  1. 专注于本地 SVG:这个插件主要是为了处理和优化项目中的本地 SVG 图标。

  2. SVG 精灵图:它会将所有的 SVG 图标合并为一个 SVG 精灵图,这可以减少 HTTP 请求并提高性能。

  3. 预加载:当项目运行时,所有图标都会预先生成,这意味着在首次加载时,所有的图标都已经可用。

  4. 高性能:内置缓存,只有在文件被修改时才会重新生成。

  5. 简单的 API:它提供了一个简单的 API 来配置和使用,使得在 Vite 项目中使用 SVG 图标变得非常简单。

总结

  • 如果你主要关心的是使用 iconify 图标库或需要一个功能丰富且可扩展的解决方案,那么 unplugin-icons 可能是一个更好的选择。

  • 如果你主要关心的是优化和管理项目中的本地 SVG 图标,并希望利用 SVG 精灵图的优势,那么 vite-plugin-svg-icons 可能更适合你。

  • 对svg 精灵图的讲解 SVG 雪碧图(SVG Sprite)是一种将多个 SVG 图标合并到单个 SVG 文件中的技术。这个合并后的文件被称为 SVG 雪碧图,它可以减少 HTTP 请求,提高性能,并使图标的管理更加方便。

以下是创建和使用 SVG 雪碧图的一般步骤:

创建 SVG 雪碧图

  1. 收集 SVG 图标:首先,收集所有要包含在雪碧图中的 SVG 图标文件。这些图标可以来自不同的来源,通常是独立的 SVG 文件。

  2. 合并 SVG 图标 :使用工具或脚本将这些独立的 SVG 文件合并成一个单独的 SVG 雪碧图文件。合并后的文件中,每个图标通常包含在 <symbol> 元素中,并分配一个唯一的标识符(id)。

  3. 定义雪碧图符号 :在合并的 SVG 文件中,你需要使用 <symbol> 元素定义每个图标。每个 <symbol> 元素都有一个 id,这个 id 通常用于引用图标。

  4. 保存雪碧图 :将合并后的 SVG 文件保存到你的项目中,通常命名为 sprite.svg 或类似的名称。

在 HTML 中使用 SVG 雪碧图

  1. 引入 SVG 雪碧图 :在你的 HTML 文件中,使用 <svg> 元素引入 SVG 雪碧图文件。通常,你会将雪碧图嵌入到页面的某个位置,例如在 <body> 的末尾。

    html 复制代码
    <svg class="hidden">
      <use xlink:href="sprite.svg#icon-id"></use>
    </svg>

    上面的代码中,xlink:href 属性指定了要使用的雪碧图文件(sprite.svg),并通过 # 指定要使用的图标的标识符(icon-id)。

  2. 使用图标 :在页面的其他地方,你可以使用 <svg> 元素来引用和显示图标。

    html 复制代码
    <svg class="icon">
      <use xlink:href="sprite.svg#icon-id"></use>
    </svg>

    在这个例子中,xlink:href 属性仍然用于指定要使用的图标,而 class 属性用于定义图标的样式。

CSS 样式

你可以使用 CSS 样式来控制 SVG 图标的大小、颜色和其他样式属性。通常,你可以为 SVG 图标添加一个类,并为这个类定义样式。

css 复制代码
.icon {
  width: 24px;
  height: 24px;
  fill: currentColor; /* 使用当前文本颜色填充图标 */
}

总的来说,SVG 雪碧图是一种优化前端项目的方式,特别是对于图标资源。它可以减少请求次数,提高性能,并简化图标的管理和使用。

具体使用 -- unplugin-icons

安装插件

bash 复制代码
npm i -D unplugin-icons

使用 unplugin-icons 插件中有一个 customCollections 属性,用来做自定义图标的加载

但 SVG 是一个 XML 格式的文件,而不是 JavaScript。为了在 JavaScript 或 TypeScript 中使用它,我们需要将其转换为一个 JavaScript 可以理解和处理的格式 所以还需要一个 SVG 文件解析的 loader

因此,unplugin-icons 提供了一个内置的 FileSystemIconLoader,这是一个专门为 SVG 设计的 loader。有了他帮助我们了简化和优化 SVG 的加载和处理过程,使其可以轻松地在前端项目中使用。

整体简单使用配置

这里列出了最基本常见的配置,更多的配置可以参考文档

js 复制代码
// vite.config.ts
import { defineConfig } from 'vite'
import Icons from 'unplugin-icons/vite'
import { FileSystemIconLoader } from 'unplugin-icons/loaders'

export default defineConfig({
  // ...
  plugins: [
   Icons({
    // @default 默认vue3
    // compiler:'vue3',

    /**
     * 按需引入这个选项会自动为你的应用安装必要的运行时。这意味着你不需要手动导入或注册图标组件,它们会自动被引入并可用。
     *  */
    autoInstall: true,

    /**
     * 这个选项允许你定义自己的图标集合。每个集合都是一个键值对,其中键是集合的名称,值是一个加载器函数,用于加载和处理图标。
     */
    customCollections: {
      /**
       * FileSystemIconLoader
       * 第一个参数是 SVG 图标的路径,文件名(不包括扩展名)将被用作图标的名称
       * 第二个参数是这是一个处理函数,用于处理加载的 SVG 内容。在这个例子中,它将 SVG 的开头替换为 <svg fill="currentColor" 。
       * 这意味着图标的颜色会使用 CSS 的 currentColor 值,从而允许你通过 CSS 控制图标的颜色。
       */
      home: FileSystemIconLoader(path.resolve('src', 'assets/home'), (svg) =>
        svg.replace(/^<svg /, '<svg fill="currentColor" ')
      )
    }
  })],
})
  • 在vue 页面上使用时候 导入格式遵守 ~icons/{collection}/{icon} 其中 collection 表示在上面配置项中 customCollections 字段的 key 集合,icon 表示集合路径下 svg 文件
vue 复制代码
<template>
  <HomeSettingSvg />
  <HomeSettingSvg style="font-size: 2em; color: red"/>
</template>

<script setup lang="ts">
// 导入 svg 图标
import HomeSettingSvg from 'virtual:icons/home/setting' // 写法一
// import HomeSettingSvg from '~icons/home/setting' // 写法二 
</script>
  • 也提供了在导入时候指定 样式用法
vue 复制代码
<template>
  <!-- <HomeSettingSvg /> -->
  <span v-html="HomeSettingSvg" />
</template>

<script setup lang="ts">
// 导入 svg 图标
import HomeSettingSvg from 'virtual:icons/home/setting?raw&width=1em&height=1em'
// import HomeSettingSvg from '~icons/home/setting'
</script>

说明如果你用了 ts 发现手动时候导入报错 ,你需要配置声明如下

ts 复制代码
declare module 'virtual:icons/*'

按需引入(推荐)

在使用的时候不想每次都导入进来 也提供了按需引入的方式 需要配置插件 unplugin-vue-components/vite 提供了配合使用的按需导入的 resolvers 'unplugin-icons/resolver'

js 复制代码
// vite.config.ts
import { defineConfig } from 'vite'
import Icons from 'unplugin-icons/vite'
import { FileSystemIconLoader } from 'unplugin-icons/loaders'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import path from 'path'

export default defineConfig({
  // ...
  plugins: [
   Icons({
    // @default 默认vue3
    // compiler:'vue3',

    /**
     * 按需引入这个选项会自动为你的应用安装必要的运行时。这意味着你不需要手动导入或注册图标组件,它们会自动被引入并可用。
     *  */
    autoInstall: true,

    /**
     * 这个选项允许你定义自己的图标集合。每个集合都是一个键值对,其中键是集合的名称,值是一个加载器函数,用于加载和处理图标。
     */
    customCollections: {
      /**
       * FileSystemIconLoader
       * 第一个参数是 SVG 图标的路径,文件名(不包括扩展名)将被用作图标的名称
       * 第二个参数是这是一个处理函数,用于处理加载的 SVG 内容。在这个例子中,它将 SVG 的开头替换为 <svg fill="currentColor" 。
       * 这意味着图标的颜色会使用 CSS 的 currentColor 值,从而允许你通过 CSS 控制图标的颜色。
       */
      home: FileSystemIconLoader(path.resolve('src', 'assets/home'), (svg) =>
        svg.replace(/^<svg /, '<svg fill="currentColor" ')
      )
    }
  }),
	Components({
    // Auto register Element Plus components
    // 自动导入 Element Plus 组件
    resolvers: [
      ElementPlusResolver(),
			// 自动导入 svg 图标 用来配合 `unplugin-icons` 使用的
      IconsResolver({
        // prefix: 'icon', // 自动引入的Icon组件统一前缀,默认为 i,设置false为不需要前缀
        enabledCollections: ['home'] // 这是可选的,默认启用 Iconify 支持的所有集合
      })
    ],
    // 指定生成的 组件的 ts 文件目录
    dts: path.resolve('types', 'components.d.ts'),

    directives: true
  })],
})

配置之后使用

vue 复制代码
<template>
  <!--[prefix]-[customCollections]-[icons]  -->
  <i-home:setting />
</template>

<script setup lang="ts">
</script>

插件 vite-plugin-svg-icons

安装

bash 复制代码
yarn add vite-plugin-svg-icons -D
# or
npm i vite-plugin-svg-icons -D
# or
pnpm install vite-plugin-svg-icons -D

简单使用

js 复制代码
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'

export default () => {
  return {
    plugins: [
      createSvgIconsPlugin({
        // 指定需要缓存的图标文件夹
        iconDirs: [path.resolve(process.cwd(), 'src/icons')],
        // 指定symbolId格式
        symbolId: 'icon-[dir]-[name]',

        /**
         * 自定义插入位置
         * @default: body-last
         */
        inject?: 'body-last' | 'body-first'

        /**
         * custom dom id
         * @default: __svg__icons__dom__
         */
        customDomId: '__svg__icons__dom__',
      }),
    ],
  }
}

在 src/main.ts 内引入注册脚本

ts 复制代码
import 'virtual:svg-icons-register'

完成上面配置后可以 到这里 svg 雪碧图已经生成

但是使用前推荐封装一个全局 svg 的vue 组件 ,在目录 /src/components/SvgIcon.vue封装参考这篇

vue 复制代码
<!-- src/components/SvgIcon/index.vue -->
<script setup lang="ts">
const props = defineProps({
  prefix: {
    type: String,
    default: "icon",
  },
  iconClass: {
    type: String,
    required: false,
  },
  color: {
    type: String,
  },
  size: {
    type: String,
    default: "1em",
  },
});
const symbolId = computed(() => `#${props.prefix}-${props.iconClass}`);
</script>
<template>
  <svg
    aria-hidden="true"
    class="svg-icon"
    :style="'width:' + size + ';height:' + size"
  >
    <use :xlink:href="symbolId" :fill="color" />
  </svg>
</template>
<style scoped>
.svg-icon {
  display: inline-block;
  outline: none;
  width: 1em;
  height: 1em;
  vertical-align: -0.15em; /* 因icon大小被设置为和字体大小一致,而span等标签的下边缘会和字体的基线对齐,故需设置一个往下的偏移比例,来纠正视觉上的未对齐效果 */
  fill: currentColor; /* 定义元素的颜色,currentColor是一个变量,这个变量的值就表示当前元素的color值,如果当前元素未设置color值,则从父元素继承 */
  overflow: hidden;
}
</style>

使用

vue 复制代码
<!-- src/components/HelloWorld.vue -->
<template>
 <el-button type="info"><svg-icon icon-class="block"/>SVG 本地图标</el-button>
</template>

更多可以参考文档

获取svg 的途径

可以从阿里图标库进行下载 合适的svg 图片 ,或者使用 iconify 网站上的图标,使用这个网站上图标需要手动安装图标库,如名,直接安装 iconify 整个库,这个库大约在 120MB 左右大小,当然你不需要担心,在生产环境只会打包你所使用到的图标

bash 复制代码
npm i -D @iconify/json

如果觉得这样下载过于庞大也可以指定下载的使用的svg 图标库,将图标集的名字替换 xxx 即可其中xxx 如图配合npm 去搜索看库是否实际存在

bash 复制代码
npm i -D @iconify-json/xxx

基础使用 iconify-json

安装完适合的 iconify-json 图标库,接下来使用

vue 复制代码
<template>
  <IconIcBaseline5g />
</template>

<script setup lang="ts">
import IconIcBaseline5g from '~icons/ic/baseline-5g'
</script>

配合 unplugin-icons 使用

如果你决定使用 @iconify/json 那么可以配合 unplugin-icons, unplugin-icons 配置中提供了自动 安装图标库集合指令 autoInstall: true ,当你运行项目时候会自动帮你安装使用的图标集合指令

现在我想按需引入的话,需要在 unplugin-vue-components 中的 IconsResolver 进行配置 enabledCollections: ['home', 'ic'] 这是可选的,默认启用 Iconify 支持的所有集合,例如按照 unplugin-icons 规则使用 @iconify/ic 的图标集合,并且也已经配置了 自动导入

html 复制代码
<i-ic:baseline-5g />
js 复制代码
// vite.config.ts
import { defineConfig } from 'vite'
import Icons from 'unplugin-icons/vite'
import { FileSystemIconLoader } from 'unplugin-icons/loaders'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import path from 'path'

export default defineConfig({
  // ...
  plugins: [
   Icons({
    // @default 默认vue3
    // compiler:'vue3',

    /**
     * 按需引入这个选项会自动为你的应用安装必要的运行时。这意味着你不需要手动导入或注册图标组件,它们会自动被引入并可用。
     *  */
    autoInstall: true,

    /**
     * 这个选项允许你定义自己的图标集合。每个集合都是一个键值对,其中键是集合的名称,值是一个加载器函数,用于加载和处理图标。
     */
    customCollections: {
      /**
       * FileSystemIconLoader
       * 第一个参数是 SVG 图标的路径,文件名(不包括扩展名)将被用作图标的名称
       * 第二个参数是这是一个处理函数,用于处理加载的 SVG 内容。在这个例子中,它将 SVG 的开头替换为 <svg fill="currentColor" 。
       * 这意味着图标的颜色会使用 CSS 的 currentColor 值,从而允许你通过 CSS 控制图标的颜色。
       */
      home: FileSystemIconLoader(path.resolve('src', 'assets/home'), (svg) =>
        svg.replace(/^<svg /, '<svg fill="currentColor" ')
      )
    }
  }),
	Components({
    // Auto register Element Plus components
    // 自动导入 Element Plus 组件
    resolvers: [
      ElementPlusResolver(),
			// 自动导入 svg 图标 用来配合 `unplugin-icons` 使用的
      IconsResolver({
        // prefix: 'icon', // 自动引入的Icon组件统一前缀,默认为 i,设置false为不需要前缀
        enabledCollections: ['ic'] // 这是可选的,默认启用 Iconify 支持的所有集合 以ic 模块为例
      })
    ],
    // 指定生成的 组件的 ts 文件目录
    dts: path.resolve('types', 'components.d.ts'),

    directives: true
  })],
})

使用 vue 组件 @iconify/vue

如果使用的是vue3

bash 复制代码
npm install --save-dev @iconify/vue

使用导入组件

js 复制代码
import { Icon } from '@iconify/vue';

在vue 上使用

html 复制代码
<Icon icon="mdi-light:home" />

这样使用之后会发现 使用svg 请求了连接 https://api.iconify.design/mdi-light.json?icons=home

当第二次刷新页面时候却没有了额外请求 此时会发现在 local storage 中多了两个 svg 信息

有这个额外请求的原因在当你使用 @iconify/vue 这个库时,它会默认地从 Iconify 的 CDN 加载图标。这意味着当你在你的 Vue 项目中使用一个图标时,它实际上是从 Iconify 的服务器上动态加载的,而不是直接从你的项目中加载的。这就是为什么会有一个 HTTP 请求的原因。

这种方法的优点是,你不需要在你的项目中包含所有的图标,从而减少了项目的大小。只有当你实际使用到某个图标时,它才会被加载。

但是,如果你不希望有这个 HTTP 请求,或者你希望图标离线可用,你可以考虑下载所需的图标并将其包含在你的项目中,或者使用其他不依赖 CDN 的图标解决方案。

使用本地 @iconify 图标库集合

以 ic 这个集合为例子下载集合

bash 复制代码
npm install --save-dev @iconify-icons/ic

使用

vue 复制代码
<template>
  <Icon :icon="baseline5g" />
</template>

<script setup lang="ts">

import baseline5g from '@iconify-icons/ic/baseline-5g'
</script>

自定义自己的 cdn svg 集合网站

js 复制代码
import { IconifyAPI } from '@iconify/vue';

// 设置自定义的 API endpoint
IconifyAPI.setAPIConfig('your-icon-set-name', {
  // 你的 CDN URL,其中 {prefix} 和 {name} 是占位符
  // {prefix} 是图标集的名称,{name} 是图标的名称
  url: 'https://your-cdn.com/path/{prefix}/{name}.json',
});

vben 自己实现的类似组件 功能

总结

svg 是一种基于可扩展标记语言(XML)的图形格式,具有 不会失真 ,更小的体积。为了在项目中更好的使用 svg, vite + vue 这种形式下 有三种

unplugin-icons , 能够识别本地 svg 文件,并且可以配合 iconify 图标库,利用 unplugin-auto-import 可以实现自动下载 使用到的 iconify 图标集

vite-plugin-svg-icons, 针对本地 svg 图标插件管理,通过配合 封装的 svg 组件,利用其精灵图的特性可以优化 svg 数量

@iconify/vue,一个已经封装好的 vue 组件用来直接使用 iconify 图标库,支持cdn 加载图片,并且会将加载后的图标存储在本地,也可以使用 本地下载好的 iconify 图标库

参考

Vue3!ElementPlus!更加优雅的使用Icon

案例+图解带你一文读懂SVG 🔥🔥(2.6W+字)

svg 详解

在vue3中,我是如何使用icon图标的

相关推荐
AiFlutter1 分钟前
Flutter-Padding组件
前端·javascript·flutter
吾即是光16 分钟前
Xss挑战(跨脚本攻击)
前端·xss
渗透测试老鸟-九青16 分钟前
通过组合Self-XSS + CSRF得到存储型XSS
服务器·前端·javascript·数据库·ecmascript·xss·csrf
xcLeigh34 分钟前
HTML5实现俄罗斯方块小游戏
前端·html·html5
天草二十六_简村人41 分钟前
spring-data-elasticsearch 3.2.4 实现桶bucket排序去重,实现指定字段的聚合搜索
java·spring boot·后端·spring·elasticsearch·架构·jenkins
发现你走远了1 小时前
『VUE』27. 透传属性与inheritAttrs(详细图文注释)
前端·javascript·vue.js
VertexGeek1 小时前
Rust学习(五):泛型、trait
前端·学习·rust
Linux运维技术栈1 小时前
企业生产环境-麒麟V10(ARM架构)操作系统部署Zookeeper单节点&集群版
linux·运维·zookeeper·架构·arm
拔剑纵狂歌1 小时前
ZooKeeper单机、集群模式搭建教程
分布式·后端·学习·zookeeper·中间件·架构·服务发现
好开心331 小时前
javaScript交互补充(元素的三大系列)
开发语言·前端·javascript·ecmascript