最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Vue 3 Dynamic Import based on Props - Stack Overflow

programmeradmin1浏览0评论

I am creating an icon ponent with unplugin-icon and in usual case i can import for example

//script
import IconCopy from '~icons/prime/copy'
//template
<IconCopy/>

it works but it feels unconvenient to import one by one if we want ot use another icon so i create a dynamic ponent named Eunoicon.vue

<script setup>
const props = defineProps({
    icon : {type:String}
})
const from = `~icons/prime/${props.icon}`
const TheIcon = await import(/* @vite-ignore */from)
console.log('ti',TheIcon)
</script>
<template>
<TheIcon/>  
</template>

but when i try to import this to a ponent it throw error Uncaught (in promise) TypeError: Failed to resolve module specifier '~icons/prime/copy'. Is any suggestion for this approach or any icon library that provide simple way something like . I've tried vue font awesome but still it's not as simple as i want.

I am creating an icon ponent with unplugin-icon and in usual case i can import for example

//script
import IconCopy from '~icons/prime/copy'
//template
<IconCopy/>

it works but it feels unconvenient to import one by one if we want ot use another icon so i create a dynamic ponent named Eunoicon.vue

<script setup>
const props = defineProps({
    icon : {type:String}
})
const from = `~icons/prime/${props.icon}`
const TheIcon = await import(/* @vite-ignore */from)
console.log('ti',TheIcon)
</script>
<template>
<TheIcon/>  
</template>

but when i try to import this to a ponent it throw error Uncaught (in promise) TypeError: Failed to resolve module specifier '~icons/prime/copy'. Is any suggestion for this approach or any icon library that provide simple way something like . I've tried vue font awesome but still it's not as simple as i want.

Share Improve this question asked Aug 21, 2022 at 8:46 Matius Nugroho AryantoMatius Nugroho Aryanto 9014 gold badges21 silver badges48 bronze badges 2
  • The auto import feature is not enough: github./antfu/unplugin-icons#auto-importing? You can't do it fully dynamic tho because the icon is imported at build time and not runtime. – kissu Commented Aug 30, 2022 at 12:11
  • Check solutions here: stackoverflow./a/71179802/4378314 – Kalnode Commented Apr 12, 2023 at 23:02
Add a ment  | 

3 Answers 3

Reset to default 1

Unfortunately, it is currently impossible to create imports dynamically. I found myself in the same problem a few months ago. My solution was to treat the icons as SVGs and to create an import file attached to my project that looked like this:

interface SvgObject {
  [key: string]: Function;
}

export function importSvg(icon: string) {
  const svg = {
    "sliders-horizontal": () => {
      return '<line x1="148" y1="172" x2="40" y2="172" fill="none" /> <line x1="216" y1="172" x2="188" y2="172" fill="none" /> <circle cx="168" cy="172" r="20" fill="none" /> <line x1="84" y1="84" x2="40" y2="84" fill="none" /> <line x1="216" y1="84" x2="124" y2="84" fill="none" /> <circle cx="104" cy="84" r="20" fill="none" /> ';
    },
}

and to create a view ponent as below which thanks to a props would retrieve the icon corresponding to the given name.


<script setup lang="ts">
import { puted } from "vue";
import { importSvg } from "@/icons/importSvg";

interface Props {
  icon: string;
}

const IconComponent = importSvg(props.icon);

</script>

<template>
  <span>
    <svg
      xmlns="http://www.w3/2000/svg"
      viewBox="0 0 256 256"
      :aria-labelledby="icon"
      v-html="IconComponent"
    ></svg>
  </span>
</template>

<style>
...
</style>
<MyIcon icon="sliders-horizontal"/>

Of course creating the import file by hand would be cumbersome, so in my case I created a python script that takes a path to an SVG icon folder and processes each of the icons to minify them and create my import file automatically. The script works for icons from the phosphor icons library. You can find the code of the script and the Vue ponent in the github repo:

https://github./fchancel/Phosphor-icon-vue-ponent

Do not hesitate to be inspired, to modify it or to use it if you decide to use Phosphor icons

Had the same problem, if i needed an icon i had to import one by one. I found a solution; Imported the Material Icons lib on my main.ts file as:

import * as MuiIcons from '@mdi/js'

Then added as a globalProperty to:

APP = createApp(App);
APP.use(createPinia())
....and so on.
APP.config.globalProperties.$muicons = { ...MuiIcons };

Then i created a "MiscelaneousStore" on my store folder (pinia in my case).

    import { defineStore } from 'pinia';
    import { getCurrentInstance } from 'vue';

    export const useMiscelaneousStore = defineStore('useMiscelaneousStore',{
    state() {
      return {
        muicons: 
      getCurrentInstance()?.appContext?.config?.globalProperties?.$muicons,
        };
    },
      });

Then in my ponent i just import my store instance with all the icons as an object.

  const miscelaneousStore = useMiscelaneousStore();

  const materialIcons = puted((): any => {
    return miscelaneousStore.muicons;
  });

We could make an utils function or posable so we can access it wherever is needed.

HTML:

<svg-icon type="mdi" :path="materialIcons.mdiAccount" :size="48" style="color: red"></svg-icon>

VUE Tools for all icons.

I don't think you'll be able to dynamically import the icons but you can import them at the base of your application, which will make globally available.

I use Font Awesome, so the implementation may differ. See below:

FontAwesome.ts:

import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { library } from "@fortawesome/fontawesome-svg-core";
import {
    faUserSecret,
    faCommentAlt,
    faCog,
    faPowerOff,
    faMoon,
    faTrophy,
} from "@fortawesome/free-solid-svg-icons";

library.add(
    faUserSecret,
    faCommentAlt,
    faCog,
    faPowerOff,
    faMoon,
    faTrophy,
);

export default FontAwesomeIcon;

main.ts:

import { createApp, provide, h } from "vue";
import FontAwesomeIcon from "./assets/icons/fontAwesome";

import App from "./App.vue";

const app = createApp(App);
app.ponent("FontAwesomeIcon", FontAwesomeIcon);

Use icon:

<font-awesome-icon :icon="['fas', 'faTrophy']" />
发布评论

评论列表(0)

  1. 暂无评论