1.问题描述
问题场景:做侧边栏的折叠效果时候需要根据settingStore.collapsed的值动态渲染图标,想用的是element-plus中的这两个图标。此处我的elementplus使用是按需引入。icon图标也是自动导入。
其他适用场景:根据路由的meta值,动态渲染icon图标,生成动态菜单。
解决方法: 使用h函数(见3解决方案)
2.探索过程
在vue3+ts中,用了自动导入图标插件unplugin-icons后,想动态渲染图标。
vite.config.ts中的相关配置:
Icons({
compiler: "vue3",
autoInstall: true,
//---start
customCollections: {
//custom图标集
custom: FileSystemIconLoader(
path.resolve(process.cwd(), "./src/assets/icons"),
svg => svg.replace(/^<svg /, "<svg fill=\"currentColor\" ")
)
}
}),
如果使用自己在assets里面放的svg图标是这样使用的(i+图标集名+图标名):
<ICustomHome/>
如果想使用element-plus里面的图标,前缀要这样写(i+图标集名ep+elementplus中的图标名)
<IEpFold />
官网中竟然没有给出示例,我最开始还以为不能自动导入element-plus中的图标,还在手动引入,手动引入是这样写的:
import {
Fold
} from "@element-plus/icons-vue";
<Fold/>
然后浏览器会解析成对应的svg
最初我用
<component
:is="settingStore.collapsed ? 'IEpFold' : 'IEpExpand'"
></component>
浏览器渲染出来的只是冰冷的
<IEpFold/>
而我们希望浏览器能将<IEpFold/>
解析成svg。
3.解决方案
方案一(不推荐):
在main.ts中全局注册这两个组件
import { Expand, Fold } from "@element-plus/icons-vue";
app.component("Expand", Expand);
app.component("Fold", Fold);
使用:
<component
:is="settingStore.collapsed ? 'Fold' : 'Expand'"
></component>
方案二:
h函数:h函数是用来创建虚拟节点(vnode)的
1.定义一个数组来存放这两个需要动态渲染的图标
let collaspsedIcons = [
{
name: "Fold",
icon: () => h(),
},
{
name: "Expand",
icon: () => h(),
},
];
2.引入需要动态渲染的图标,并分别放入h函数
import Fold from "~icons/ep/fold";
import Expand from "~icons/ep/expand";
tips:为什么是这样的路径?
可以先在其他地方写<IEpFold/>
,然后ctrl+左键,就能进入components.d.ts这个存放组件的文件,这里就有路径,复制过来即可。
3.新建type.ts,用来给collaspsedIcons数组定义 类型(也可以不定义name)
import type { Component } from "vue";
export interface CollaspsedIcon {
name: string;
icon: Component;
}
此处icon的值就是一个component组件
4.补全1中的代码
import Fold from "~icons/ep/fold";
import Expand from "~icons/ep/expand";
import { CollaspsedIcon } from "./type.ts";
let collaspsedIcons: Array<CollaspsedIcon> = [
{
name: "Fold",
icon: () => h(Fold),
},
{
name: "Expand",
icon: () => h(Expand),
},
];
5.进行动态渲染:
<el-icon @click="changeIcon" size="18">
<component
:is="
settingStore.collapsed
? collaspsedIcons[0].icon
: collaspsedIcons[1].icon
"
></component>
</el-icon>
参考文章:
element中自动引入icon