jpkleemans / vite-svg-loader

Vite plugin to load SVG files as Vue components
MIT License
554 stars 58 forks source link

当页面同时使用多个相同图标出现 ID 冲突导致 SVG无法正常显示 #122

Open WangJincheng4869 opened 10 months ago

WangJincheng4869 commented 10 months ago

svgo 中可以添加前缀,但只能解决使用不同图标,如果使用相同的图标依旧会有ID冲突问题。

WangJincheng4869 commented 10 months ago

没法解决,所以我弃用该插件自己进行实现,基本代码如下


const instance = getCurrentInstance()!;

图标的样式
const iconStyle = computed(() => {
  let style: StyleValue = {};
  let transform = '';
  if (props.rotate) {
    transform += `rotate(${props.rotate}) `;
  }
  if (props.rotateX) {
    transform += `rotateX(${props.rotateX}) `;
  }
  if (props.rotateY) {
    transform += `rotateY(${props.rotateY}) `;
  }
  if (transform) {
    style.transform = transform;
  }
  return style;
});

watchEffect(() => {
  import(`../../assets/svg/${props.name}.svg?raw`).then(dom => {
    let svgDom = dom.default
      .replace(/(id=")(.*?")/gi, `$1${instance.uid}-$2`)
      .replace(/(url\(#)(.*?\))/gi, `$1${instance.uid}-$2`)
      .replace(/(href="#)(.*?")/gi, `$1${instance.uid}-$2`);
    console.log(instance.uid);
    if (iconStyle.value.transform) {
      let parser = new DOMParser();
      let doc = parser.parseFromString(svgDom, 'image/svg+xml');
      let svg = doc.querySelector('svg')!;
      svg.style.transform = iconStyle.value.transform;
      iconDom.value = svg.outerHTML;
    } else {
      iconDom.value = svgDom;
    }
  });
});
How2j-online commented 7 months ago

这样封装一下

<script setup lang="ts">
defineOptions({
  name: "SvgIcon"
});
import type { Component } from "vue";
import { computed } from "vue";

const props = defineProps<{
  name: string;
}>();
const modules = import.meta.glob("@/assets/icons/*.svg", {
  as: "component",
  eager: true
});
// icon lower name
const newName = computed(() => {
  return props.name.toLowerCase();
});
// 获取对应svg组件
const currentComponent = computed(() => {
  const fileName = `/${newName.value}.svg`;
  let findMod;
  for (const path in modules) {
    const mod = modules[path];
    if (path.endsWith(fileName)) {
      findMod = mod as Component;
    }
  }
  return findMod;
});
</script>

<template>
  <component :is="currentComponent"></component>
</template>

<style scoped lang="less"></style>

我的版本

"vite-svg-loader": "^4.0.0",
"vue": "^3.3.4",
"typescript": "~5.1.6",
WangJincheng4869 commented 6 months ago

这样封装一下

<script setup lang="ts">
defineOptions({
  name: "SvgIcon"
});
import type { Component } from "vue";
import { computed } from "vue";

const props = defineProps<{
  name: string;
}>();
const modules = import.meta.glob("@/assets/icons/*.svg", {
  as: "component",
  eager: true
});
// icon lower name
const newName = computed(() => {
  return props.name.toLowerCase();
});
// 获取对应svg组件
const currentComponent = computed(() => {
  const fileName = `/${newName.value}.svg`;
  let findMod;
  for (const path in modules) {
    const mod = modules[path];
    if (path.endsWith(fileName)) {
      findMod = mod as Component;
    }
  }
  return findMod;
});
</script>

<template>
  <component :is="currentComponent"></component>
</template>

<style scoped lang="less"></style>

我的版本

"vite-svg-loader": "^4.0.0",
"vue": "^3.3.4",
"typescript": "~5.1.6",

你这段代码可以解决 svg 代码里用到 id,页面上重复使用图标,会出现 id 重复而无法正常显示的情况吗?

raohuiyong commented 5 months ago

svgo有个插件配置prefixIds,为每个id添加前缀(前缀根据文件名生成)。可以保持id的唯一

WangJincheng4869 commented 5 months ago

svgo有个插件配置prefixIds,为每个id添加前缀(前缀根据文件名生成)。可以保持id的唯一

只能解决不同图标的问题,如果一个图标被多次引用,依旧冲突

Dylan0916 commented 5 months ago

I'm also facing this problem. is there any solution for this lib?