Vue3如何引入SVG图标?一篇文章快速学会!
1. 前言
在开发 Vue 项目时,我们常使用前端组件库,如 Element 和 Ant Design,但这些库的内置图标通常较少,无法满足某些特定项目的需求(如医疗、财务等)。因此,很多时候我们需要引入外部 SVG 图标。
2. 效果展示
接下来,我们将学习如何在 Vue3 项目中引入 SVG 图标。
3. SVG 简介
SVG 是可伸缩矢量图形(Scalable Vector Graphics)的简称,使用 XML 来描述二维图形。与 JPG、PNG 一样,SVG 是一种图形格式,但因为它是矢量图,无论放大或缩小都不会失真。
如果想深入了解 SVG,可以参考以下网站:
4. 下载 SVG 图标
推荐使用阿里巴巴的 Iconfont 网站下载 SVG 图标:
- 选择图标并点击下载按钮
- 设置颜色和尺寸后下载 SVG 格式
- 可以将多个图标添加到购物车,批量下载
接下来,我们将在 Vue 项目中引入这些 SVG 图标。
5. Vue3 引入 SVG 图标
5.1 安装插件
我们使用 Vite 脚手架开发 Vue3 项目,并借助 vite-plugin-svg-icons
插件将 SVG 图标转换为 Vue 组件。
首先,安装相关插件:
npm i vite-plugin-svg-icons -D
npm i fast-glob -D # 如果出现错误,再安装 fast-glob
5.2 在 main.js
中注册插件
在 main.js
中导入插件:
import 'virtual:svg-icons-register';
5.3 配置 vite.config.js
修改 vite.config.js
文件:
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
import { resolve } from "path";
const pathSrc = resolve(__dirname, "src");
export default defineConfig({
plugins: [
vue(),
createSvgIconsPlugin({
// 指定需要缓存的图标文件夹
iconDirs: [resolve(pathSrc, "assets/icons")],
// 指定 symbolId 格式
symbolId: "icon-[dir]-[name]",
}),
],
resolve: {
alias: {
'@': resolve(__dirname, "./src"),
},
},
});
5.4 封装展示 SVG 图标的组件
我们封装一个 SvgIcon
组件,用来展示 SVG 图标:
<template>
<svg aria-hidden="true" :fill="color" :style="'width:' + size + ';height:' + size">
<use :xlink:href="symbolId" />
</svg>
</template>
<script setup>
import { computed } from "vue";
const props = defineProps({
name: {
type: String,
default: "",
},
color: {
type: String,
default: "black",
},
size: {
type: String,
default: "1em",
},
});
const symbolId = computed(() => `#icon-${props.name}`);
</script>
5.5 使用组件
使用封装好的 SvgIcon
组件:
<template>
<div class="content">
<SvgIcon name="client" size="10rem" />
<SvgIcon name="client" size="10rem" color="red" />
<SvgIcon name="client" size="10rem" color="green" />
</div>
</template>
<script setup>
import SvgIcon from "@/components/SvgIcon/index.vue";
</script>
<style lang="scss" scoped></style>
6. 批量导入 SVG 图标
我们可以使用 import.meta.glob
来动态导入所有 SVG 图标,并获取图标名称:
<template>
<div class="content">
<SvgIcon
v-for="(iconName, index) in allIconNames"
:key="index"
:name="iconName"
size="5rem"
/>
</div>
</template>
<script setup>
import SvgIcon from "@/components/SvgIcon/index.vue";
import { onMounted, ref } from "vue";
const allIconNames = ref([]); // 存储所有图标名称
onMounted(() => {
loadAllIcons();
});
const loadAllIcons = () => {
const icons = import.meta.glob("@/assets/icons/*.svg");
for (const icon in icons) {
const iconName = icon.split("/src/assets/icons/")[1].split(".")[0];
allIconNames.value.push(iconName);
}
};
</script>
<style lang="scss" scoped></style>
7. 开发 SVG 搜索组件
在这个组件中,我们将使用 element-plus
作为前端组件库,开发一个图标选择组件,方便用户搜索和选择 SVG 图标。
7.1 SelectIcon
组件完整代码
<template>
<div class="content">
<el-input
style="width: 100%"
v-model="inputIconValue"
readonly
placeholder="点击选择图标"
@click="visible = !visible"
>
<template #prepend>
<SvgIcon :size="20" :name="inputIconValue" />
</template>
</el-input>
<el-popover
shadow="none"
:visible="visible"
placement="bottom-end"
trigger="click"
width="400"
>
<el-row gutter="10">
<el-col :span="18">
<el-input
v-model="filterValue"
placeholder="输入图标名称"
clearable
@input="filterIcon"
/>
</el-col>
<el-col :span="6">
<el-button @click="closeIcon()">关闭</el-button>
</el-col>
</el-row>
<el-scrollbar height="300px">
<div class="icon-list">
<el-tooltip
v-for="(iconName, index) in filterIconNames"
:key="index"
:content="iconName"
placement="bottom"
effect="light"
>
<div class="icon-item" @click="handleSelect(iconName)">
<SvgIcon :name="iconName" />
</div>
</el-tooltip>
</div>
</el-scrollbar>
</el-popover>
</div>
</template>
<script setup>
import SvgIcon from "@/components/SvgIcon/index.vue";
import { ref, onMounted, toRef } from "vue";
const visible = ref(false);
const allIconNames = ref([]);
const filterIconNames = ref([]);
const filterValue = ref("");
const emit = defineEmits(["update:modelValue"]);
const props = defineProps({
modelValue: {
type: String,
default: "",
},
});
const inputIconValue = toRef(props, "modelValue");
onMounted(() => {
loadAllIcons();
});
const loadAllIcons = () => {
const icons = import.meta.glob("@/assets/icons/*.svg");
for (const icon in icons) {
const iconName = icon.split("/src/assets/icons/")[1].split(".")[0];
allIconNames.value.push(iconName);
}
filterIconNames.value = allIconNames.value;
};
const filterIcon = () => {
if (filterValue.value) {
filterIconNames.value = allIconNames.value.filter(iconName =>
iconName.includes(filterValue.value)
);
} else {
filterIconNames.value = allIconNames.value;
}
};
const handleSelect = (iconName) => {
emit("update:modelValue", iconName);
visible.value = false;
};
const closeIcon = () =>
{
visible.value = false;
filterValue.value = "";
filterIconNames.value = allIconNames.value;
};
</script>
<style lang="scss" scoped>
.icon-list {
display: flex;
flex-wrap: wrap;
.icon-item {
display: flex;
justify-content: center;
padding: 5px;
margin: 5px;
width: 10%;
cursor: pointer;
border: 1px solid #ccc;
&:hover {
border-color: var(--el-color-primary);
transform: scale(1.1);
transition: all 0.2s;
}
}
}
</style>
8. 项目完整代码
可以下载完整项目,记得运行 npm install
来安装相关依赖:
链接: 百度网盘 提取码: 1234