element组件库系列(二)--如何优雅地使用element-plus自带的图标库

1,056 阅读3分钟

引言

这是element组件库系列文章,主要是平时使用element组件库的一些过程和心得,文章篇幅不定,有长有短,但主打一个实用(可能实用不一定是对你实用,不实用请轻喷)。在element-plus中,引入官方自带的图标从原有的class引入方式变成了导入组件的方式。

<script>
import {Document} from "@element-plus/icons-vue"
</script>
<template>
<el-icon :size="20" color="#000000">
  <Document/>
</el-icon>
</template>

通过按需导入的方式,需要时导出即可。

然而,这会造成一些问题:在一些高度封装的场景,典型的就是中后台的路由菜单中,我们希望通过配置自动生成菜单,并在每一项菜单中显示图标。

就像这样:

image-20230817213317430

于是,我们需要在路由配置中的meta属性加上一个icon字段,用来告诉渲染菜单时要一起渲染icon,但这时,icon的值明显是一个字符串,怎么办呢?别着急,笔者就向大家介绍一下如何实现。

版本说明和开发环境

前置知识

阅读本文你需要一些有关渲染函数的基础,如不是很了解,请先移步这里

各依赖版本

packagesversion
element-plus2.2.15
vue33.4.3

开发环境

环境说明(版本)
操作系统macOS
Node16.14.2

正文开始

分析过程

首先明确我们的需求,给定一个icon,这其实就是告诉要渲染的icon名字;但我们的icon又需要导入,导入的是一个组件。在这,突破口就是我们需要一个name和组件的映射关系,如果知道js中的Map对象,就可以有:

const iconsMap = new Map<string,Component>()

iconsMap为存放这个映射关系的映射集合,我们传入icon的name,就可以取出想要渲染的组件。而把这个组件渲染出来,由于其是我们所导入的一个组件值,我们可以利用h函数将其渲染为VNode

image-20230817224040476

于是可以进一步得到:

<el-icon>{h(iconsMap.get(iconName))}</el-icon>

到这里,这个组件最终的模样已经非常清晰了,el-icon有两个参数 sizecolor,我直接将其作为组件的props,给这个组件起名ZIcon。那么代码为:

<script lang="tsx">
import * as  icons from "@element-plus/icons-vue"
import {Component,h,defineComponent,toRefs} from "vue";
const iconsMap =new Map<string,Component>()
for (let icon in icons){
  //驼峰变量变小写并加上el-, ArrowLeft ===> el-arrow-left
  const iconName ='el-'+icon.split(/(?=[A-Z])/)
      .map(str=>str.toLowerCase()).join('-');
  //@ts-ignore
  iconsMap.set(iconName,icons[icon])
}
export default defineComponent({
  props:{
    iconName:{
      type:String,
      required:true
    },
    iconSize:{
      type:Number,
      default:20
    },
    iconColor:{
      type:String,
      default:'#000000'
    }
  },
  setup(props){
    //只是为了加入 @ts-ignore,不然ts在报错
    function getIcon(){
      //@ts-ignore
      return h(iconsMap.get(props.iconName))
    }
    return {
      getIcon,
      ...toRefs(props)
    }
  },
  render(){
    return <el-icon size={this.iconSize} color={this.iconColor}>{this.getIcon()}</el-icon>
  }
})
</script>

可以看到,ZIcon有三个参数,icon的名字、大小和颜色。icon的名字通过形如el-arrow-left传入,这样项目中以后引入其他图标库时也方便开发中一眼看懂这是element-plus自带的图标,更为语义化。

以上就是如何优雅使用element-plus自带图标库的方式了,希望能帮到你,让我们下篇再见👋!

2023-11-21更新

为了方便还在使用js的小伙伴,增加js版本的写法,需要的小伙伴粘贴这个就行了。

<script setup>
import * as icons from "@element-plus/icons-vue";
import { h } from "vue";

/**
 * @type {Map<string,import('vue').Component>}
 */
const iconsMap = new Map();
for (let icon in icons) {
  //驼峰变量变小写并加上el-, ArrowLeft ===> el-arrow-left
  const iconName =
    "el-" +
    icon
      .split(/(?=[A-Z])/)
      .map((str) => str.toLowerCase())
      .join("-");
  //@ts-ignore
  iconsMap.set(iconName, icons[icon]);
}
const props = defineProps({
  iconName: {
    type: String,
    required: true
  },
  iconSize: {
    type: Number,
    default: 20
  },
  iconColor: {
    type: String,
    default: "#000000"
  }
});

//具体渲染的组件
function EIcon() {
  return h(iconsMap.get(props.iconName));
}
</script>

<template>
  <el-icon :size="props.iconSize" :color="props.iconColor">
    <EIcon />
  </el-icon>
</template>