登峰造极境

  • WIN
    • CSharp
    • JAVA
    • OAM
    • DirectX
    • Emgucv
  • UNIX
    • FFmpeg
    • QT
    • Python
    • Opencv
    • Openwrt
    • Twisted
    • Design Patterns
    • Mysql
    • Mycat
    • MariaDB
    • Make
    • OAM
    • Supervisor
    • Nginx
    • KVM
    • Docker
    • OpenStack
  • WEB
    • ASP
    • Node.js
    • PHP
    • Directadmin
    • Openssl
    • Regex
  • APP
    • Android
  • AI
    • Algorithm
    • Deep Learning
    • Machine Learning
  • IOT
    • Device
    • MSP430
  • DIY
    • Algorithm
    • Design Patterns
    • MATH
    • X98 AIR 3G
    • Tucao
    • fun
  • LIFE
    • 美食
    • 关于我
  • LINKS
  • ME
Claves
长风破浪会有时,直挂云帆济沧海
  1. 首页
  2. Platforms
  3. WEB
  4. 正文

vue3如何加载外部SVG并且可以执行颜色

2024-11-13

解决方案,基于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>

效果如下图:

标签: 暂无
最后更新:2024-11-13

代号山岳

知之为知之 不知为不知

点赞
< 上一篇
下一篇 >

COPYRIGHT © 2099 登峰造极境. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

蜀ICP备14031139号-5

川公网安备51012202000587号