【问题标题】:Vue 3 Dynamic Import based on PropsVue 3 基于 Props 的动态导入
【发布时间】:2023-02-13 23:51:36
【问题描述】:

我正在用 unplugin-icon 创建一个图标组件,通常情况下我可以导入

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

它有效,但如果我们想使用另一个图标,一个一个导入感觉不方便,所以我创建了一个名为 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>

但是当我尝试将其导入组件时,它会抛出错误Uncaught (in promise) TypeError: Failed to resolve module specifier '~icons/prime/copy'. 对这种方法或任何提供简单方法的图标库的任何建议,如 .我已经尝试过 vue font awesome 但它仍然没有我想要的那么简单。

【问题讨论】:

标签: javascript vue.js icons vite dynamic-import


【解决方案1】:

不幸的是,目前无法动态创建导入。几个月前我发现自己遇到了同样的问题。我的解决方案是将图标视为 SVG,并创建一个附加到我的项目的导入文件,如下所示:

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" /> ';
    },
}

并创建一个如下所示的视图组件,这要归功于道具将检索与给定名称相对应的图标。


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

interface Props {
  icon: string;
}

const IconComponent = importSvg(props.icon);

</script>

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

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

当然,手动创建导入文件会很麻烦,所以在我的例子中,我创建了一个 python 脚本,它接受一个 SVG 图标文件夹的路径,并处理每个图标以缩小它们并自动创建我的导入文件。 该脚本适用于 phosphor 图标库中的图标。 您可以在 github 存储库中找到脚本代码和 Vue 组件:

https://github.com/fchancel/Phosphor-icon-vue-component

如果您决定使用 Phosphor 图标,请毫不犹豫地获得灵感、修改或使用它

【讨论】:

    【解决方案2】:

    我认为您无法动态导入图标,但您可以在应用程序的基础上导入它们,这将使全球可用。

    我使用 Font Awesome,所以实现可能会有所不同。见下文:

    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;
    

    主.ts:

    import { createApp, provide, h } from "vue";
    import FontAwesomeIcon from "./assets/icons/fontAwesome";
    
    import App from "./App.vue";
    
    const app = createApp(App);
    app.component("FontAwesomeIcon", FontAwesomeIcon);
    

    使用图标:

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

    【讨论】:

      【解决方案3】:

      有同样的问题,如果我需要一个图标,我必须一个一个地导入。 我找到了解决办法;将 Material Icons 库导入到我的 main.ts 文件中:

      import * as MuiIcons from '@mdi/js'
      

      然后作为 globalProperty 添加到:

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

      然后我在我的商店文件夹(在我的例子中是 pinia)上创建了一个“MiscelaneousStore”。

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

      然后在我的组件中,我只导入我的商店实例,并将所有图标作为一个对象。

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

      我们可以制作一个 utils 函数或可组合函数,以便我们可以在需要的任何地方访问它。

      HTML:

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

      VUE Tools for all icons.

      【讨论】:

        猜你喜欢
        • 2021-09-29
        • 2021-05-11
        • 1970-01-01
        • 2017-06-04
        • 2021-10-04
        • 1970-01-01
        • 2021-03-30
        • 2019-04-23
        • 2020-12-27
        相关资源
        最近更新 更多