在使用 unplugin-icon
图标库的时候遇到的图标动态渲染问题,这里记录一下
正常直接使用
这样的图标是正常渲染的,但是当遇到路由图标那种需要根据数据渲染出图标,就不行了,这里的解决方法是封装图标渲染的组件
绑定的时候就通过h
函数进行渲染
建一个icon.ts
文件
import { h } from 'vue';
import SvgIcon from '@/components/Icon/SvgIcon.vue';
/**
* 图标渲染
* - 用于vue的render函数
*/
export const useIconRender = () => {
interface IconConfig {
/**
* 图标名称(iconify图标的名称)
* - 例如:mdi-account 或者 mdi:account
*/
icon?: string;
/**
* 本地svg图标文件名(assets/svg文件夹下)
*/
localIcon?: string;
/** 图标颜色 */
color?: string;
/** 图标大小 */
fontSize?: number;
}
interface IconStyle {
color?: string;
fontSize?: string;
}
/**
* 图标渲染
* @param config
* @property icon - 图标名称(iconify图标的名称), 例如:mdi-account 或者 mdi:account
* @property localIcon - 本地svg图标文件名(assets/svg文件夹下)
* @property color - 图标颜色
* @property fontSize - 图标大小
*/
const iconRender = (config: IconConfig) => {
const { color, fontSize, icon, localIcon } = config;
const style: IconStyle = {};
if (color) {
style.color = color;
}
if (fontSize) {
style.fontSize = `${fontSize}px`;
}
if (!icon && !localIcon) {
window.console.warn('没有传递图标名称,请确保给icon或localIcon传递有效值!');
}
return () => h(SvgIcon, { icon, localIcon, style });
};
return {
iconRender
};
};
然后创建个SvgIcon
组件
<template>
<template v-if="renderLocalIcon">
<svg aria-hidden="true" width="1em" height="1em" v-bind="bindAttrs">
<use :xlink:href="symbolId" fill="currentColor" />
</svg>
</template>
<template v-else>
<Icon v-if="icon" :icon="icon" v-bind="bindAttrs" />
</template>
</template>
<script setup lang="ts">
import { computed, useAttrs } from 'vue';
import { Icon } from '@iconify/vue';
/**
* 图标组件
* - 支持iconify和本地svg图标
* - 同时传递了icon和localIcon,localIcon会优先渲染
*/
interface Props {
/** 图标名称 */
icon?: string;
/** 本地svg的文件名 */
localIcon?: string;
}
const props = defineProps<Props>();
const attrs = useAttrs();
const bindAttrs = computed<{ class: string; style: string }>(() => ({
class: (attrs.class as string) || '',
style: (attrs.style as string) || ''
}));
const symbolId = computed(() => {
const { VITE_ICON_LOCAL_PREFFIX: preffix } = import.meta.env;
const defaultLocalIcon = 'no-icon';
const icon = props.localIcon || defaultLocalIcon;
return `#${preffix}-${icon}`;
});
/** 渲染本地icon */
const renderLocalIcon = computed(() => props.localIcon || !props.icon);
</script>
<style scoped></style>
vite的plugin
这样引
import { resolve } from 'path'
import Icons from 'unplugin-icons/vite'
import VueMacros from 'unplugin-vue-macros/vite';
import IconsResolver from 'unplugin-icons/resolver';
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { FileSystemIconLoader } from 'unplugin-icons/loaders'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import { getSrcPath } from '../utils';
/**
* * unplugin-icons插件,自动引入iconify图标
* usage: https://github.com/antfu/unplugin-icons
* 图标库: https://icones.js.org/
*/
export default function unplugin(viteEnv) {
const { VITE_ICON_PREFFIX, VITE_ICON_LOCAL_PREFFIX } = viteEnv;
const srcPath = getSrcPath();
/** 本地svg图标路径 */
const localIconPath = `${srcPath}/assets/svg`;
/** 本地svg图标集合名称 */
const collectionName = VITE_ICON_LOCAL_PREFFIX.replace(`${VITE_ICON_PREFFIX}-`, '');
return [
VueMacros({}),
AutoImport({
imports: ['vue', 'vue-router'],
dts: false,
}),
Icons({
compiler: 'vue3',
customCollections: {
[collectionName]: FileSystemIconLoader(localIconPath, svg =>
svg.replace(/^, '
VITE_ICON_PREFFIX
和VITE_ICON_LOCAL_PREFFIX
其实就是个全局常量 代表图标的前缀而已
常量这块 直接写死都一样的
使用的时候直接导出封装的useIconRender
import { useIconRender } from '@/utils';
const { iconRender } = useIconRender();
iconRender({ icon: 'carbon:user-avatar'}),
然后到渲染的地方呢 读取出你绑定的字段
直接渲染就可以了
本地的图标好像有点问题,还在研究为啥动态渲染不了,后面发现问题了再改
或者有没有大佬看看,是啥原因导致本地svg动态导入不进去