求解 vite+vue3 项目中关于动态图标的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
qq309187341
V2EX    Vue.js

求解 vite+vue3 项目中关于动态图标的问题

  •  
  •   qq309187341 2023-04-03 08:59:29 +08:00 3752 次点击
    这是一个创建于 990 天前的主题,其中的信息可能已经有所发展或是发生改变。
    项目使用了 vite+vue3 。然后配置了 unplugin-auto-import 、unplugin-vue-components 和 unplugin-icons 这三个插件。虽然实现了自动图标导入以及自动按需加载对应的图标功能。但是出现了一个问题,那就是菜单返回的动态图标没办法处理。
    然后目前遇上了一个问题,就是后端返回的图标名称是字符串的。但是我使用<component :is="xxx">需要一个组件。我想过用 eval()方法将后台的字符串转化成对象。但是这样会存在安全问题。
    有没有大佬教一下怎么处理。
    期望的需求是不需要显示的进行导入同时具备按需加载,自动导入的功能。
    21 条回复    2024-09-17 14:48:05 +08:00
    xiaohundun
        1
    xiaohundun  
       2023-04-03 09:15:52 +08:00
    yunyuyuan
        2
    yunyuyuan  
       2023-04-03 09:17:55 +08:00
    我是自己写的组件,不用第三方插件,动态加载没问题<svg-icon :name="your-variable" />
    https://blog.yunyuyuan.net/articles/9074
    qq309187341
        3
    qq309187341  
    OP
       2023-04-03 09:21:20 +08:00
    @yunyuyuan 你这个是项目内的 svg 图标吧。但是如果你需要使用第三方的图标呢?还是只能显示的导入再按需加载。
    yunyuyuan
        4
    yunyuyuan  
       2023-04-03 09:23:39 +08:00
    @qq309187341 1 楼已经提到了,unplugin-icons 不支持动态加载
    lupkcd
        5
    lupkcd  
       2023-04-03 09:25:06 +08:00
    使用 iconify 在线请求的方式,内部可搭私服
    qq309187341
        6
    qq309187341  
    OP
       2023-04-03 09:26:30 +08:00
    @xiaohundun 我通过 autoImport 插件实现了动态图标,但是现在存在一个问题,使用动态图标需要接受比如 let icon = IEpPlus 。 而后台返回的是 “IEpPlus”是一个字符串。我使用 eval()方法也成功实现了 “IEpPlus”转化成 IEpPlus 。但是 eval()有安全问题,我想问问还有什么别的方式,或者其他插件或者现有插件就有提供相关方式的
    clf
        7
    clf  
       2023-04-03 09:36:21 +08:00
    我看腾讯的 starter 脚手架里用的是 vite-svg-loader ,加载的 svg 是一个组件。

    import MyIcon from 'xxx/xxx.svg'

    上面这样引入 svg 文件就行。
    Huelse
        8
    Huelse  
       2023-04-03 09:47:42 +08:00
    上图床更可控点
    kingterrors
        9
    kingterrors  
       2023-04-03 09:52:35 +08:00   3
    我说前几天好像看过一个类似的帖子。。。果然是你发的。。。请不要频繁面向 V2EX 编程。
    而且上一个帖子我就说了,写个 demo ,有兴趣研究的人,直接在 demo 上手。方便你我他,然而你忽略了我的建议。
    任何新手在提问前,都应该尽可能将问题描述清楚,并方便解决人来尽快解决。
    甚至你在自己写个 demo 的时候,问题说不定就解决了。
    而打那么多字,你也费劲,别人理解也费劲。
    请下次提问带上 demo 。
    关联: t/928689#r_12888230
    momo2278
        10
    momo2278  
       2023-04-03 09:56:12 +08:00   1
    推荐 unocss 的图标处理方案,直接加 class 名,无需额外的组件,自定义的图标可以配置好自动导入使用,动态图标直接写在配置中的 safelist 或者只要页面上有对应的类名能触发到就行
    han3sui
        11
    han3sui  
       2023-04-03 10:12:31 +08:00
    试试 new URL(url, [base])
    renmu
        12
    renmu  
       2023-04-03 10:13:30 +08:00 via Android
    搞不懂,你们后端返回图片是不返回链接的吗?
    qq309187341
        13
    qq309187341  
    OP
       2023-04-03 10:18:12 +08:00
    @renmu 因为这个是图标,而且是后台管理系统的菜单图标。所以可能就是这个图标的字符串
    xiaohundun
        14
    xiaohundun  
       2023-04-03 10:45:03 +08:00
    我觉得应该用 10 楼的方案,用 class 来做,要是你能处理 eval 的安全问题,那现在的也行
    xiaohundun
        15
    xiaohundun  
       2023-04-03 10:45:45 +08:00
    @xiaohundun #14 至少我见过的管理端的图标都是 classname
    shakukansp
        16
    shakukansp  
       2023-04-03 12:20:47 +08:00
    写个脚本
    比如你图标放 /assets/icons
    每次新加图标就运行一下脚本
    这个脚本就做一件事情,读取这个目录的文件名然后生成一个 ts 文件
    import BasicActtive from '~icons/assets-icons/basic-acttive';
    export {
    BasicActtive,
    }
    类似这种各式
    我项目里就是这么处理
    后端返回的是 icon 字符串
    前端导入
    import Bookmark from '~icons/carbon/bookmark';
    import * as icons from '~/assets/icons';

    export const getIcon = (name?: string) => {
    if (!name) return Bookmark;
    return Reflect.get(
    icons,
    camelcase(name, { pascalCase: true, preserveConsecutiveUppercase: true }),
    );
    };
    shakukansp
        17
    shakukansp  
       2023-04-03 12:24:18 +08:00
    ~icons/assets-icons/是 unplugin-icons 配置的自定义目录
    用 vite-svg-loader 也可以
    gitignore
        18
    gitignore  
       2023-04-03 14:20:40 +08:00
    @qq309187341 #6

    <component :is="vue: IEpPlus" /> vue 自动会将 `vue:` 前缀字符串解析到对应的组件,op 是这个意思吗?

    https://cn.vuejs.org/api/built-in-special-attributes.html#is

    vue 帮你调用 `resolveComponent`
    LucasW
        19
    LucasW  
       2023-04-03 14:32:13 +08:00
    duanluan
        20
    duanluan  
       2024-09-13 18:59:23 +08:00
    src/components/Iconify.vue:

    <template>
    <el-icon>
    <Icon :icon="icon"/>
    </el-icon>
    </template>

    <script setup lang="ts">
    import {Icon} from '@iconify/vue';

    const props = defineProps({
    icon: {
    type: String,
    default: null,
    }
    });
    </script>

    src/components/RecursiveMenu.vue:

    <template>
    <template v-for="item in menuTree">
    <template v-if="item.children && item.children.length > 0">
    <el-sub-menu :index="String(item.id)">
    <template #title>
    <Iconify :icon="item.icon"/>
    <span>{{ item.name }}</span>
    </template>
    <RecursiveMenu :menu-tree="item.children"/>
    </el-sub-menu>
    </template>
    <template v-else>
    <el-menu-item :index="String(item.id)">
    <Iconify :icon="item.icon"/>
    <span>{{ item.name }}</span>
    </el-menu-item>
    </template>
    </template>
    </template>

    <script setup lang="ts">
    import Iconify from "@/components/Iconify.vue";

    const props = defineProps({
    menuTree: {
    type: Array as PropType<any[]>,
    required: true
    }
    });
    </script>
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5199 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 35ms UTC 08:04 PVG 16:04 LAX 00:04 JFK 03:04
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86