前言
本文示例是官方的 vite 脚手架, svg 图标使用的是阿里的字体图标,自行下载
新建文件,例:src/plugins/svg-loader.js
findSvgFile 函数会查找当前文件路径下的所有 svg 文件, 包括子文件夹里面的
需保证 svg 文件不重名
import { readdirSync, readFileSync } from 'fs';
const svgLabel = /<svg([^>+].*?)>/;
const pathLabel = /<path([^>+].*?)>/g;
const clearReturn = /(\r)|(\n)/g;
const clearWidthHeight = /(width|height)="([^>+].*?)"/g;
const hasViewBox = /(viewBox="[^>+].*?")/g;
/**
* @Description 替换 svg 文件信息
* @param dir svg 目录
*/
function findSvgFile(dir) {
const svgRes = [];
const dirEntries = readdirSync(dir, {
withFileTypes: true
});
for (const dirent of dirEntries) {
if (dirent.isDirectory()) {
svgRes.push(...findSvgFile(dir + dirent.name + '/'));
} else {
const svg = readFileSync(dir + dirent.name)
.toString()
.replace(clearReturn, '')
.replace(svgLabel, ($1, $2) => {
let width = 0;
let height = 0;
let content = $2.replace(clearWidthHeight, (s1, s2, s3) => {
s3 = s3.replace('px', '');
if (s2 === 'width') {
width = s3;
} else if (s2 === 'height') {
height = s3;
}
return '';
});
if (!hasViewBox.test($2)) {
content += `viewBox="0 0 ${width} ${height}"`;
}
return `<symbol id="${dirent.name.replace('.svg', '')}" ${content}>`;
})
// 替换svg图标原先fill
.replace(pathLabel, ($1, $2) => {
return `<path fill="currentColor" ${$2}>`;
})
.replace('</svg>', '</symbol>');
svgRes.push(svg);
}
}
return svgRes;
}
/**
* @Description 加载svg 文件
* @param path svg图标文件路径
*
*/
export default function (path) {
if (path === '') return;
const res = findSvgFile(path);
return {
name: 'svg-transform',
// vite 插件 直接替换 html 页签内容
transformIndexHtml(html) {
return html.replace(
'<body>',
`
<body>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
style="position: fixed; width: 0; height: 0"
>
${res.join('')}
</svg>
</body>
`
);
}
};
}
配置 vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import svgLoader from './src/plugins/svg-loader';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
svgLoader('./src/assets/')
]
});
直接使用
#号后面为 svg 文件名
<template>
<svg class="svg-icon" aria-hidden="true">
<use xlink:href="#like"></use>
</svg>
</template>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
/* 填充色 */
fill: currentColor;
color: #8a8a8a;
overflow: hidden;
}
.svg-icon:hover {
color: #d81e06;
}
</style>
封装成组件,例:src/components/SvgIcon.vue
<template>
<svg class="svg-icon" aria-hidden="true">
<use :xlink:href="iconName"></use>
</svg>
</template>
<script lang="ts" setup>
import { computed } from 'vue';
const props = defineProps({
name: {
type: String,
required: true
}
});
const iconName = computed(() => `#${props.name}`);
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
/* 填充色 */
fill: currentColor;
color: inherit;
overflow: hidden;
}
</style>
组件使用
name 值为 svg 文件名
<template>
<SvgIcon class="svg-icon" name="like" />
</template>
<script setup>
import SvgIcon from './components/SvgIcon.vue';
</script>
<style scoped>
.svg-icon {
color: #8a8a8a;
}
.svg-icon:hover {
color: #d81e06;
}
</style>
评论区