解决方案,基于vite-plugin-svg-icons,做一些小的修改即可实现。
注意:网上下载的部分svg,需要手动清除svg文件内的fill属性,否则无法在外部修改颜色。
一、安装vite-plugin-svg-icons
安装vite-plugin-svg-icons并修改vite.config.ts如下:
export default defineConfig({
plugins: [
vue(),
createSvgIconsPlugin({
// 指定需要缓存的图标文件夹
iconDirs: [path.resolve(process.cwd(), "src/assets/icons")],
// 指定symbolId格式
symbolId: "icon-[dir]-[name]",
customDomId: "__svg__icons__dom__",
inject: "body-first",
}),
],
二、新建SvgIcon.vue组件
<template>
<svg aria-hidden="true" class="svg-external-icon svg-icon">
<use :href="symbolId" :fill="color" :cursor="cursor"/>
</svg>
</template>
<script setup lang="ts">
import { defineComponent,ref,watchEffect, computed, defineProps } from "vue";
import {CryptoUtils} from "../../utils/CryptoUtils"
const symbolId = ref("demo");
const props = defineProps( {
prefix: {
type: String,
default: "icon",
},
name: {
type: String,
default: "demo"
},
color: {
type: String,
default: "#333",
},
cursor: {
type: String,
default: "auto",
},
url: {
type: String,
default: "",
},
});
watchEffect(() => {
if(props.url!==null && props.url!==undefined && props.url!=''){ //SVG来自外部连接
// Step 1 先根据URL计算一个MD5HASH
let svgDomId = `${props.prefix}-${CryptoUtils.MD5(props.url)}`;
// Step 2 检查DOM中是否已经存在该SVG
const parentElement = document.getElementById("__svg__icons__dom__");
const childElement = document.getElementById(svgDomId);
if(parentElement && !childElement){ //当存在父级DOM,但不存在子DOM时,代表该SVG是第一次加载,则手动插入到DOM中
fetch(props.url).then(response=>{
if(!response.ok)
{
throw new Error(`加载SVG矢量图片失败,链接:${props.url}`)
}
return response.text();
})
.then(svgContent=>{
//若svgContent不为空,且DOM中没有该ID(再找一次的原因是,加载DOM是异步的,不再找一次会插入很多相同ID的图标)
if(svgContent&&!document.getElementById(svgDomId)){
//使用DOM解析器解析SVG
const parser = new DOMParser();
const svgDoc = parser.parseFromString(svgContent, 'image/svg+xml');
const svgContainer = svgDoc.documentElement;
const svgPaths = svgContainer.children;
const symbolElement = document.createElementNS('http://www.w3.org/2000/svg', 'symbol');
//仅将SVG的Path添加到新Element中
Array.from(svgPaths).forEach(svgPath => {
if(svgPath.nodeName.toLowerCase()==="path")
symbolElement.appendChild(svgPath); // 将每个子元素添加到 <symbol>
});
//保持原有SVG的属性和新symbol一致
Array.from(svgContainer.attributes).forEach(attr => {
if(attr.name==="viewBox"){
symbolElement.setAttribute('viewBox', attr.value);
}
if(attr.name==="class"){
symbolElement.classList.add(attr.value);
}
});
symbolElement.id = svgDomId;
parentElement.appendChild(symbolElement)
}
})
.catch(error=>{
console.log(`加载SVG矢量图片失败,链接:${error}`)
})
}
symbolId.value = `#${svgDomId}`;
}else{
symbolId.value = `#${props.prefix}-${props.name}`; //Svg来自本地存储
}
})
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
overflow: hidden;
}
.svg-external-icon {
display: inline-block;
}
</style>
三、使用方法
<div>
<h2>常规图标</h2>
<div>
<co-icon name="flower"></co-icon>
<co-icon name="flower" color="#00ff00"></co-icon>
</div>
<h2>颜色调整(Tips:部分Svg不支持)</h2>
<div>
<co-icon name="flower" color="var(--iios-color-primary)"></co-icon>
<co-icon name="flower" color="var(--iios-color-info)"></co-icon>
<co-icon name="flower" color="var(--iios-color-warning)"></co-icon>
<co-icon name="flower" color="var(--iios-color-danger)"></co-icon>
<co-icon name="flower" color="var(--iios-color-error)"></co-icon>
</div>
<h2>大小调整</h2>
<div>
<span style="font-size: 10px;"><co-icon name="error" color="var(--iios-color-primary)"></co-icon></span>
<span style="font-size: 20px;"><co-icon name="create" color="var(--iios-color-info)"></co-icon></span>
<span style="font-size: 30px;"><co-icon name="delete" color="var(--iios-color-warning)"></co-icon></span>
<span style="font-size: 40px;"><co-icon name="down" color="var(--iios-color-danger)"></co-icon></span>
<span style="font-size: 50px;"><co-icon name="flower" color="var(--iios-color-error)"></co-icon></span>
</div>
<h2>鼠标光标形状</h2>
<div>
<span style="font-size: 40px;"><co-icon name="flower" cursor="crosshair" color="var(--iios-color-primary)"></co-icon></span>
<span style="font-size: 40px;"><co-icon name="flower" cursor="pointer" color="var(--iios-color-info)"></co-icon></span>
<span style="font-size: 40px;"><co-icon name="flower" cursor="move" color="var(--iios-color-warning)"></co-icon></span>
<span style="font-size: 40px;"><co-icon name="flower" cursor="e-resize" color="var(--iios-color-danger)"></co-icon></span>
<span style="font-size: 40px;"><co-icon name="flower" cursor="wait" color="var(--iios-color-error)"></co-icon></span>
</div>
<h2>外部连接</h2>
<div>
<co-icon style="font-size: 10px;" url="https://www.dev.com.cn/iios-minio/iios-meta-images/iios-console/org/icon/down.svg" color="var(--iios-color-primary)"></co-icon>
<co-icon style="font-size: 20px;" url="https://www.dev.com.cn/iios-minio/iios-meta-images/iios-console/org/icon/flower002.svg" color="var(--iios-color-info)"></co-icon>
<co-icon style="font-size: 30px;" url="https://www.dev.com.cn/iios-minio/iios-meta-images/iios-console/org/icon/flower002.svg" color="var(--iios-color-warning)"></co-icon>
<co-icon style="font-size: 40px;" url="https://www.dev.com.cn/iios-minio/iios-meta-images/iios-console/org/icon/down.svg" color="var(--iios-color-danger)"></co-icon>
<co-icon style="font-size: 50px;" url="https://www.dev.com.cn/iios-minio/iios-meta-images/iios-console/org/icon/flower002.svg" color="var(--iios-color-error)"></co-icon>
</div>
</div>
效果如下图: