【问题标题】:Dynamic inline importing raw SVG in Vue.js & Vite在 Vue.js 和 Vite 中动态内联导入原始 SVG
【发布时间】:2023-01-28 15:46:09
【问题描述】:

所以我尝试使用 Vite 上的内联导入将 SVG 作为字符串导入我的 Vue 组件,如下所示

<script>
const getSvgIcon = async (name) => {
  const module = await import(`../icons/${name}.svg?raw`)
  return module.default
}

export default {
  props: {
    name: String,
  },
  data() {
    return {
      svg: null,
    }
  },
  watch: {
    name: {
      async handler(name) {
        this.svg = await getSvgIcon(name)
      },
      immediate: true,
    },
  },
}
</script>

<template>
  <div v-html="svg"></div>
</template>

这在 npm run dev 模式下运行时工作得很好。

但是,问题发生在运行npm run build 时,我最终得到Error: Unknown variable dynamic import 显然是因为我使用的是?raw 后缀。

有没有解决方案或者这是 Vite 的障碍?

【问题讨论】:

  • 我认为这是一个 Vite 错误。我建议报告 GitHub 问题。

标签: javascript vue.js vuejs3 vite


【解决方案1】:

正如 @tony19 评论的那样,这可能是一个错误。我打开了一个问题,你可以关注here

作为使您的代码正常工作的解决方法,请执行以下操作:

第1步:

将所有 SVG 转换为 Vue 组件。这样,您可以进行更好的管理。为此,您只需编辑文件名,将 .svg 替换为 .vue 并将内容包装在 template 标签内。

如果你想保留 svg 文件,你可以使用 vite-svg-loader 插件,你可以这样做:

import IconComponent from './my-icon.svg?component'

第2步:

创建一个 SVG 图标组件:

<script>
import { defineAsyncComponent } from 'vue';

export default {
  props: {
    name: {
      type: String,
      required: true,
    },
  },

  computed: {
    dynamicComponent() {
      const name = this.name;

      return defineAsyncComponent(() => import(`./icons/${name}.vue`));
    },
  },
};
</script>

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

步骤 3

现在您可以导入 SvgIcon.vue 并使用 SVG 图标的名称,如下所示:

<script>
import SvgIcon from './components/SvgIcon.vue'

export default {
  components: {
    SvgIcon
  }
}
</script>

<template>
  <SvgIcon name="user" />
</template>

See it live on Stackblitz


如果你喜欢上面的方法,我最近写了一篇关于它的文章:

Unified SVG icons with Vite, Vue 3, Quasar and Pinia

【讨论】:

  • 这很有趣,这是解决这个问题的一种更优雅的方法,但是使用 vite-svg-loader 会导致相同的动态导入错误,因为再次使用 ?component 后缀。我不想将图标转换为 vue 模板,因为它们不是一个或两个。但是如果这个错误需要很长时间才能修复,我想我将不得不接受这个......
  • 嘿,您的博客文章似乎不再有效,而且没有它的存档版本。你还在某个地方放着这篇博文吗?
  • @Alice 你现在可以再检查一下吗?
【解决方案2】:

看看我自己创建的这个例子。

<template>
    <i v-html="svg" />
</template>

<script lang="ts" setup>
    import { computed } from 'vue';

    const props = defineProps({
        icon: {
            type: String,
            required: true,
        },
        src: {
            type: String,
            default: '',
        },
    });
    const path = props.src ? props.src : '';
    const file = `${path}icon-${props.icon}`;
    const modules = import.meta.glob('../../assets/icons/**/*.svg', {
        as: 'raw',
        eager: true,
    });
    const svg = computed(() => {
        return modules['../../assets/icons/' + file + '.svg'] ?? modules['../../assets/icons/icon-logo-cone.svg'];
    });
</script>

这就是在一个漂亮且简约的组件中动态加载 SVG 所需的全部内容。

啊,不要忘记,您还可以使用纯 css 更改 svg 的颜色。

用法:

<UiIcon
    class="w-4 text-gray-600"
    icon="search"
/>

【讨论】:

  • 最后一个不需要插件的内部解决方案,谢谢!不过,它可能会有所优化,atm 每次调用组件时我们都会将整个文件夹全局化。也许值得只做一次并存储图标列表
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-08-03
  • 2022-11-20
  • 1970-01-01
  • 2021-01-05
  • 2019-03-28
  • 2017-04-12
  • 2021-06-03
相关资源
最近更新 更多