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