Vite 中SvgIcon更好的实现
vite中的svg
vite 本身支持将 svg 资源引入为 静态url 或 字符串内容raw,参见 静态资源处理
但这并不是我们期待的引入内容,所以会有一些方案实现:
vite-svg-loader
vite-svg-loader 使项目支持引入svg为 component,且支持开启svgo
vite-plugin-svg-icons
使用说明见 vite-plugin-svg-icons
- 预加载 在项目运行时就生成所有图标,只需操作一次 dom
- 高性能 内置缓存,仅当文件被修改时才会重新生成
通过生成指定目录下所有 svg 为雪碧图,即将多个 SVG 图标整合到一个 SVG 文件中,每个图标作为这个大 SVG 文件的一部分,它们可以通过 <symbol>
标签的 id 被单独引用和使用。
SVG 雪碧图的优点有:只需要发送一次 HTTP 请求就可以获取所有图标,可以减少 HTTP 请求的次数,提高网页的加载速度。
同时,SVG 雪碧图内的每个图标还可以被单独引用和缓存,增加了图标的复用性。
如果项目svg增多,svg雪碧图生成文件会更大,且无法单独引用的特性存在性能短板;
更好的尝试
既然 vite-svg-loader
支持将svg资源引入为 component,尝试在项目中将指定目录下所有svg引入为component(当然是动态引入),并将其作为异步组件被使用
使用方面,我们可以通过定义一个全局组件 SvgIcon 方便使用
import { defineComponent, defineAsyncComponent, h } from "vue";
const svgModules = import.meta.glob("@/assets/images/svg/**/*.svg", {
query: "?component",
});
export default defineComponent({
name: "SvgIcon",
props: {
name: { type: String, default: "" },
},
setup(props) {
const SvgComponent = defineAsyncComponent(
svgModules[`/src/assets/images/svg/${props.name}.svg`]
);
return () => h(SvgComponent);
},
});
或者SFC单文件组件形式
<script setup>
import { defineAsyncComponent } from "vue";
const props = defineProps({
name: { type: String, default: "" },
});
const svgModules = import.meta.glob("@/assets/images/svg/**/*.svg", {
query: "?component",
});
const SvgComponent = defineAsyncComponent(
svgModules[`/src/assets/images/svg/${props.name}.svg`]
);
</script>
<template>
<SvgComponent />
</template>
<style lang="" scoped></style>
如上,通过 import.meta.glob
批量动态导入所有svg为component,使用组件时传入svg名称或路径+名称即可
<script setup>
</script>
<template>
<!-- 分别显示 svg/edit.svg 和 svg/tool/save.svg -->
<SvgIcon name="edit"></SvgIcon>
<SvgIcon name="tool/edit"></SvgIcon>
</template>
<style lang="less" scoped></style>