vue + vite 图标导入总结

SVG 的使用

在页面中我们会使用到各种图标,为了保证图标在放大缩小不失真,通常会采用 SVG 来作为图标。

SVG(Scalable Vector Graphics)是一种基于XML的矢量图像格式,它可以用来创建清晰的、可缩放的图形,无论放大多少倍都不会失真。在Web开发中,SVG常用于制作图标,因为它具有以下优点:

  • 清晰度:SVG图标在任何分辨率下都能保持清晰。
  • 可编辑性:SVG是文本格式,可以使用文本编辑器进行修改。
  • 尺寸小:SVG图标文件通常比位图(如PNG或JPEG)更小,尤其在需要多个尺寸时。
  • 动画支持:SVG支持动画,可以通过CSS或JavaScript实现动态效果。
  • 可编程性:可以使用CSS或JavaScript直接操作SVG元素。

以下是SVG图标在HTML中直接使用的简单代码示例:

html<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        /* 你可以通过CSS来控制SVG图标 */
        .my-icon {
            width: 24px;
            height: 24px;
            fill: currentColor; /* 这会让SVG填充颜色跟随父元素的颜色 */
        }
    </style>
</head>
<body>
    <!-- 直接内联SVG图标 -->
    <svg class="my-icon" viewBox="0 0 24 24" id="icon-example">
        <path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7l3.59 3.59L17 7.41 15.59 9 12 12.59z"></path>
    </svg>

    <!-- 或者通过<use>标签引用外部SVG文件中的图标 -->
    <svg class="my-icon">
        <use xlink:href="#icon-example"></use> <!-- icons.svg是SVG文件,icon-example是图标在文件中的ID -->
    </svg>
</body>
</html>

在这个例子中,我们创建了两个SVG图标。第一个是内联SVG,直接在HTML中定义了图标路径。第二个是通过 <use> 标签引用了一个外部SVG文件中的图标。viewBox 属性定义了SVG的视口,d 属性包含了描述图形路径的数据。

注意,如果你使用 <use> 标签,你需要确保外部SVG文件已经被正确引入到你的HTML文档中,通常是通过<script><link> 标签。

阿里的 iconfont 的 symbol 引用就是通过 script 标签引入的,其原理是将所有图标的 svg 标签及内部 path 标签定义为字符串放在 iconfont.js 文件中,当 js 文件引入到页面后会将图标的字符串通过 innerHTML 转化为 DOM 标签作为 body 的第一个子元素插入到页面,代码如下:

i = function() {
    var t, e = document.createElement("div");
    e.innerHTML = n._iconfont_svg_string_4570457,
    (e = e.getElementsByTagName("svg")[0]) && (e.setAttribute("aria-hidden", "true"),
    e.style.position = "absolute",
    e.style.width = 0,
    e.style.height = 0,
    e.style.overflow = "hidden",
    e = e,
    (t = document.body).firstChild ? s(e, t.firstChild) : t.appendChild(e))
}
,
document.addEventListener ? ~["complete", "loaded", "interactive"].indexOf(document.readyState) ? setTimeout(i, 0) : (o = function() {
    document.removeEventListener("DOMContentLoaded", o, !1),
    i()
}

在这里插入图片描述

通过插件导入 icon 图标

vite-plugin-svg-icons 方式

针对每个图标都是一个 svg 文件这种情况,如果要单个引入就比较麻烦。假设图标都放在 src/assets/svg 目录下

在这里插入图片描述

我们可以使用 vite-plugin-svg-icons 插件来完成,其功能如下:

  • 预加载所有图标,项目运行时生成所有图标,只需操作DOM一次
  • 内置高速缓存功能,只有在文件被修改时才会重新生成
# 安装
yarn add vite-plugin-svg-icons -D
# or
npm i vite-plugin-svg-icons -D
# or
pnpm install vite-plugin-svg-icons -D

安装完成后需要在 vite.config.ts 进行如下配置:

import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'

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

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

        /**
         * 定义 svg 标签的 id 值
         * @default: __svg__icons__dom__
         */
        customDomId: '__svg__icons__dom__',
      }),
    ],
  }
}

src/main.ts 文件中引入注册脚本

import 'virtual:svg-icons-register'

以下是插入到页面的 svg 标签及图标,可以看出所有的图标都有加载

在这里插入图片描述

对于 svg 图标一般是修改其颜色和大小,通常会套一个 i 标签来定义,同时会传入一个图标名称,这三者作为组件的属性,这样就可以定义一个 ICON 组件了

<!-- src/components/icon.vue -->
<style>
.icon {
    height: 1em;
    width: 1em;
    line-height: 1em;
    display: inline-flex;
    justify-content: center;
    align-items: center;
    position: relative;
    fill: currentColor;
    font-size: inherit;
}
</style>
<template>
    <i class="icon" :style="{ color: color, fontSize: size + 'px' }">
        <svg aria-hidden="true">
            <use :xlink:href="symbolId"></use>
        </svg>
    </i>
</template>
<script setup lang="ts">
import { computed, unref } from 'vue';

const props = defineProps({
    prefix: {
      type: String,
      default: 'icon',
    },
    // icon name
    iconName: {
        type: String,
        required: true,
    },
    // icon color
    color: {
        type: String,
        default: '#000'
    },
    // icon size
    size: {
        type: Number,
        default: 16
    }
})
const symbolId = computed(() => `#${props.prefix}-${props.iconName}`)
</script>

使用

<template>
    <icon iconName="add" />
    <icon iconName="delete" />
    <icon iconName="export" />
    <icon iconName="edit" />
</template>
<script setup lang="ts">
	import Icon from "@/components/Icon.vue";
</script>

效果如下图:

在这里插入图片描述

该插件原理大致总结为:根据 iconDirs 提供的图标所在的文件夹自动查找所有的 SVG 文件,将这些 SVG 文件全部添加到 svg 标签下,每一个图标对应一个 symbol 标签,每个标签的 id 为配置项中 symbolId 。通过 use :xlink:href="symbolId" 引用图标。

unplugin-icons 方式

GitHub - unplugin/unplugin-icons 是一个用于优化图标管理与使用的开发插件,它允许开发者以一种高效且自动化的形式在项目中使用图标,无需手动创建或导入每一个图标组件。使用此插件不需要将图标先下载到本地,可以从一些开源的图标库中自动导入图标。其使用方式如下:

安装

npm i -D unplugin-icons

安装图标库:使用 Iconify 作为图标库

# 安装完整版本
npm i -D @iconify/json
# 按图标集安装,例如,要安装 Material Design Icons
npm i -D @iconify-json/mdi

vite.config.ts 进行如下配置:

// vite.config.ts
import Icons from 'unplugin-icons/vite'

export default defineConfig({
  plugins: [
    Icons({ /* options */ }),
  ],
})

使用

<script setup>
import IconAccessPointCheck from '~icons/mdi/access-point-check';
import IconAccountBox from '~icons/mdi/account-box'
</script>

<template>
  <icon-access-point-check/>
  <icon-account-box style="font-size: 2em; color: red"/>
</template>

效果如下图:

在这里插入图片描述

为了提高工作效率,通过在配置项中启用“ autoInstall ”选项,可以让 unplugin-icons 来负责安装工作,此时就不需要安装图标库了

// vite.config.ts
import Icons from 'unplugin-icons/vite'

export default defineConfig({
  plugins: [
    Icons({ 
      // experimental
      autoInstall: true,
    }),
  ],
})

在这里插入图片描述

unplugin-icons 的图标解析与转换过程总结如下:

  1. 图标名称识别
  • 在Vue模板或JSX中,开发者使用图标名称(如 <i-mdi-home></i-mdi-home>),unplugin-icons 会通过代码分析识别这些图标名称。
  1. 图标解析
  • 图标名称映射:根据配置的图标集,unplugin-icons 查找图标名称与实际图标资源之间的映射关系。这通常涉及到读取图标集的元数据,如JSON文件,里面记录了每个图标的名称和对应的SVG路径。

  • 图标资源提取:一旦找到图标名称对应的资源位置,插件会读取SVG文件或从图标库API获取SVG数据。

  1. 图标转换
  • SVG到Vue组件:获取到SVG数据后,unplugin-icons 将SVG内容转换为Vue组件代码。这个过程可能包括:
    • 图标优化:对SVG进行优化,比如去除不必要的属性、标准化样式等,确保图标在不同浏览器和平台上的表现一致。
    • 组件模板构造:构造Vue组件模板,将SVG内容包裹在Vue的<template>标签中,并添加必要的属性和事件绑定。
    • 动态导入处理:如果配置了按需加载,插件会生成动态导入代码,确保图标只在真正使用时加载。
  • 组件注册:生成的Vue组件需要在项目中注册,以便在模板中直接使用。unplugin-icons 通常会自动处理组件的注册,可能通过全局注册或按需注册的方式。
  1. 自动导入
  • 依赖注入:通过与unplugin-auto-import的集成,unplugin-icons 在编译时自动插入必要的导入语句,使得开发者无需手动导入图标组件。
  1. 最终输出
  • 编译产物:经过上述步骤,原本的图标名称在编译后的代码中被替换为实际的Vue组件调用,同时图标组件按需加载和自动导入的逻辑也被正确插入。最终,构建工具输出的代码中包含了最小化且优化过的图标组件,既减少了包体积,又简化了开发流程。

项目中注册,以便在模板中直接使用。unplugin-icons 通常会自动处理组件的注册,可能通过全局注册或按需注册的方式。

  1. 自动导入
  • 依赖注入:通过与unplugin-auto-import的集成,unplugin-icons 在编译时自动插入必要的导入语句,使得开发者无需手动导入图标组件。
  1. 最终输出
  • 编译产物:经过上述步骤,原本的图标名称在编译后的代码中被替换为实际的Vue组件调用,同时图标组件按需加载和自动导入的逻辑也被正确插入。最终,构建工具输出的代码中包含了最小化且优化过的图标组件,既减少了包体积,又简化了开发流程。

整个过程确保了图标资源的高效利用,同时保持了代码的清晰和易维护性。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部