动态内联导入 Vue.js & Vite 中的原始 SVG



因此,我尝试在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后缀。

到目前为止,有没有解决方案,或者这是维特的一个障碍?

正如@tony19所评论的,这可能是一个错误。我打开了一期,你可以在这里关注

不过,作为使代码正常工作的变通方法,请遵循以下步骤:

步骤1:

将所有SVG转换为Vue组件。这样,你可以有更好的管理。为了做到这一点,您只需编辑文件名,将其从.svg替换为.vue,并将内容包装在template标记中。

如果你想保留svg文件,你可以使用vite-svg加载程序插件,这样你就可以做到:

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>

在Stacklitz 上实时观看


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

统一的SVG图标与Vite,Vue 3,Quasar和Pinia

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

<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"
/>

这里是另一个围绕vite-svg加载器的包装器

创建SVG图标组件InlineSvg.vue:

<script setup>
import { shallowRef } from 'vue'
const props = defineProps({
src: {
type: Object,
required: true
}
})
let svgComponent = shallowRef(null)
props.src
.then((module) => {
svgComponent.value = module.default
})
</script>
<template>
<component :is="svgComponent"/>
</template>

然后使用:

<script setup>
import InlineSvg from '@/components/InlineSvg.vue'
</script>
<template>
<InlineSvg
class="w-32 h-32"
:src="import('@/assets/svg/logo.svg')"/>
</template>

这种方法的缺陷在于,它在生产构建中为InlineSvg组件的每次使用创建了许多块。

我觉得我找到了最好的解决方案:(Vite文档:https://vitejs.dev/guide/features.html#glob-进口

<script>
import { defineAsyncComponent } from 'vue'
export default {
props: {
name: {
type: String,
required: true
}
},
data() {
return {
icons: import.meta.glob(`./**/*.svg`)
}
},
computed: {
icon() {
return defineAsyncComponent(() => this.icons[`./${this.name}.svg`]())
},
}
}
</script>
<template>
<component :is="icon" :class="className" />
</template>

最新更新