前言:
对于icon,前端的第一反应就是采用iconfont来做,对于多数场景当然是没有问题的,甚至后续项目中出现自定义icon只需要ui将设计传到iconfont平台就行了,但是毕竟还是经过了第三方平台的,所以我采用了iconify方案
需求:
我现在的项目之前是用的MDI的图标库,后续因为ui陆续将icon设计出来了,所以也需要上传我们自己的自定义图标,所以需要兼容两种情况
步骤:
1.选用插件:unplugin-icons与unplugin-auto-import/vite插件----通过插件实现图标的自动导入和Vue组件的按需导入,无需手动导入图标,直接在模板中使用图标名称即可。这种方式更加自动化和便捷,但需要配置相应的插件和解析器。
相关配置(vite.config.js)
// icon相关插件
import AutoImport from 'unplugin-auto-import/vite'
import Icons from 'unplugin-icons/vite'
// icon 自动引入解析器
import IconsResolver from 'unplugin-icons/resolver'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { FileSystemIconLoader } from 'unplugin-icons/loaders'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
AutoImport({
imports: ['vue'],
resolvers: [ElementPlusResolver(),IconsResolver({
componentPrefix: "icon",
enabledCollections: ["datalink", "mdi"],
})],
}),
Icons({
// 默认的比例为1
scale:1,
compiler: 'vue3',// 指定编译器
autoInstall: true,// 自动安装(如果你用了element的icon但你没有下载对应的.json文件,它会自动帮你下载,如果你没这个需求,就不用设置)
// 配置自定义的图标(里面直接放svg就行了)
customCollections: {
datalink: FileSystemIconLoader('./src/components/icon-iconify/icon-svg')
}
}),
]
})
配置完成后,就可以在项目中直接使用了,插件可以自动的按需加载图标,不需要手动导入
<template>
<h1>
icon方案测试1
</h1>
<!--使用其他的icon图标集,这里展示的element puls的(需要配置)-->
<IconEpCellphone></IconEpCellphone>
<!--使用自定义的svg图-->
<IconDatalinkE/>
<icon-mdi-bowl></icon-mdi-bowl>
</template>
问题:
但是接下来就引出一个新的问题了,如果我使用不同的图标库,这个使用图标组件的名称都有所区别比如说MDI:就是icon-mdi-xxxx,element puls: 就是icon-ep-xxxx 更别说我们的自定义图标了,所以为了统一,最好封装一个组件,这样我们使用时就比较统一了(接下来也就是本篇文章的重点)
在github上,如果你去留意多数人提的问题,会发现,很多人都在询问能否通过动态的方法去生成icon图标呢,作者的统一回答都是 NO,原因是:
由于unplugin-vue-components的工作机制,无法从动态字符串推断组件。 (unplugin-icons
仅在构建时解析图标),如果你在运行后尝试动态生成,那是没有作用的
相关问题:
Unable to use <Component :is="" · Issue #260 · unplugin/unplugin-icons · GitHub
<!-- 通过is切换是不行的 -->
<template #title>
<el-icon v-if="menu.meta.icon"><component :is="menu.meta.icon"/></el-icon>
<span>{{ menu.meta.title }}</span>
</template>
<menu-item v-for="(item, key) in menu.children" :key="key" :menu="item" :basePath="pathResolve" />
</el-sub-menu>
解决:
github上也有人提出对应的解决方案(提前将要使用的icon准备好就行了),这样就是在构建时完成了(如果还是不行,大概率是缺少unplugin-auto-import/vite插件的配置导致的),要实现下方的功能
https://github.com/unplugin/unplugin-icons/issues/5
<template>
<div class="p-icon" :class="[iconColor]">
<component :is="icon" :width="iconSize" :height="iconSize"></component>
</div>
</template>
<style lang="less">
.p-icon {
svg {
fill: red;
}
&.p-icon-primary {
svg {
fill: red;
}
}
}
</style>
<script setup>
import { computed } from 'vue';
const props = defineProps({
icon: {
type: String,
default: '',
},
size: {
type: [Number, String],
default: 20,
},
primary: {
type: Boolean,
default: false,
},
});
// 自定义图标集(:的右边部分就是插件的使用,根据你的配置名称可能会有所不同需要注意)
const items = {
'jellyfish': IconDatalinkJellyfish,
'arrow-down': IconDatalinkArrowDown,
'arrow-left': IconDatalinkArrowLeft,
'arrow-right': IconDatalinkArrowRight,
};
const icon = computed(() => {
const iconName = props.icon.split('icon-')[1];
if (items[iconName]) {
return items[iconName];
}
// 当图标不存在时,默认展示
return items['jellyfish'];
});
const iconSize = computed(() => {
return props.size;
});
const iconColor = computed(() => {
if (props.primary) {
console.log('是primary');
return 'p-icon-primary';
}
return '';
});
</script>
小知识点:
如果你试图改变svg的颜色,你发现改变不了,你可以去仔细看看,你的svg文件,内部是否存在一个默认fill属性,你需要将其删除,通过css给svg上颜色就行了