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
的图标解析与转换过程总结如下:
- 图标名称识别
- 在Vue模板或JSX中,开发者使用图标名称(如
<i-mdi-home></i-mdi-home>
),unplugin-icons
会通过代码分析识别这些图标名称。
- 图标解析
- 图标名称映射:根据配置的图标集,
unplugin-icons
查找图标名称与实际图标资源之间的映射关系。这通常涉及到读取图标集的元数据,如JSON文件,里面记录了每个图标的名称和对应的SVG路径。 - 图标资源提取:一旦找到图标名称对应的资源位置,插件会读取SVG文件或从图标库API获取SVG数据。
- 图标转换
-
SVG到Vue组件:获取到SVG数据后,
unplugin-icons
将SVG内容转换为Vue组件代码。这个过程可能包括:- 图标优化:对SVG进行优化,比如去除不必要的属性、标准化样式等,确保图标在不同浏览器和平台上的表现一致。
- 组件模板构造:构造Vue组件模板,将SVG内容包裹在Vue的
<template>
标签中,并添加必要的属性和事件绑定。 - 动态导入处理:如果配置了按需加载,插件会生成动态导入代码,确保图标只在真正使用时加载。
-
组件注册:生成的Vue组件需要在项目中注册,以便在模板中直接使用。
unplugin-icons
通常会自动处理组件的注册,可能通过全局注册或按需注册的方式。
- 自动导入
- 依赖注入:通过与
unplugin-auto-import
的集成,unplugin-icons
在编译时自动插入必要的导入语句,使得开发者无需手动导入图标组件。
- 最终输出
- 编译产物:经过上述步骤,原本的图标名称在编译后的代码中被替换为实际的Vue组件调用,同时图标组件按需加载和自动导入的逻辑也被正确插入。最终,构建工具输出的代码中包含了最小化且优化过的图标组件,既减少了包体积,又简化了开发流程。
整个过程确保了图标资源的高效利用,同时保持了代码的清晰和易维护性。
文章转自:https://juejin.cn/post/7377191678862475301