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

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

import MyIcon from 'xxx/xxx.svg'

上面这样引入 svg 文件就行。
Huelse
2023-04-03 09:47:42 +08:00
上图床更可控点
kingterrors
2023-04-03 09:52:35 +08:00
我说前几天好像看过一个类似的帖子。。。果然是你发的。。。请不要频繁面向 V2EX 编程。
而且上一个帖子我就说了,写个 demo ,有兴趣研究的人,直接在 demo 上手。方便你我他,然而你忽略了我的建议。
任何新手在提问前,都应该尽可能将问题描述清楚,并方便解决人来尽快解决。
甚至你在自己写个 demo 的时候,问题说不定就解决了。
而打那么多字,你也费劲,别人理解也费劲。
请下次提问带上 demo 。
关联: https://www.v2ex.com/t/928689#r_12888230
fox2081
2023-04-03 09:56:12 +08:00
推荐 unocss 的图标处理方案,直接加 class 名,无需额外的组件,自定义的图标可以配置好自动导入使用,动态图标直接写在配置中的 safelist 或者只要页面上有对应的类名能触发到就行
han3sui
2023-04-03 10:12:31 +08:00
试试 new URL(url, [base])
renmu
2023-04-03 10:13:30 +08:00
搞不懂,你们后端返回图片是不返回链接的吗?
qq309187341
2023-04-03 10:18:12 +08:00
@renmu 因为这个是图标,而且是后台管理系统的菜单图标。所以可能就是这个图标的字符串
xiaohundun
2023-04-03 10:45:03 +08:00
我觉得应该用 10 楼的方案,用 class 来做,要是你能处理 eval 的安全问题,那现在的也行
xiaohundun
2023-04-03 10:45:45 +08:00
@xiaohundun #14 至少我见过的管理端的图标都是 classname
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
2023-04-03 12:24:18 +08:00
~icons/assets-icons/是 unplugin-icons 配置的自定义目录
用 vite-svg-loader 也可以
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
2023-04-03 14:32:13 +08:00
duanluan
108 天前
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>

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/929289

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX