仿 ElementPlus 组件库(三)—— Icon 组件实现

292 阅读2分钟

在前端开发中,组件库的使用能够极大地提高开发效率,ElementPlus 就是一款非常受欢迎的 Vue 组件库。今天我们来探讨如何模仿 ElementPlus 打造功能完备且风格一致的 Icon 组件。

一、什么是 Icon 组件

Icon 组件,即图标组件,在用户界面中扮演着至关重要的角色。它以简洁直观的图形符号呈现,用于传达特定的信息或功能,帮助用户快速识别和操作。无论是在导航栏、按钮、菜单,还是各种提示信息中,Icon 都无处不在。相较于纯文字表述,Icon 能够更高效地吸引用户注意力,提升界面的美观度和交互性,使整个应用更加易用和友好。

二、实现 Icon 组件

(一)安装Fontawesome图标库

    npm i --save @fortawesome/fontawesome-svg-core
    npm i --save @fortawesome/free-solid-svg-icons
    npm i --save @fortawesome/vue-fontawesome@latest-3

添加对应依赖

  • main.ts
import { library } from '@fortawesome/fontawesome-svg-core'
import { fas } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
//...
library.add(fas)
//...
createApp(App)
.component('font-awesome-icon',FontAwesomeIcon)    //全局注册组件
//...

(二)组件目录

components
├── Icon
    ├── Icon.vue
    ├── types.ts
    ├── style.css    

(三)初步实现Icon组件

  • 默认情况下,Vue 组件会将未被声明为 props 的属性自动添加到组件的根元素上,这被称为属性继承。当设置 inheritAttrs: false 时,会禁用这种默认行为,即未声明为 props 的属性不会被添加到组件的根元素(这里是 <i class="yl-icon">)上。结合模板中的 v-bind="$props",可以确保所有属性都被传递给 font-awesome-icon 组件,而不是应用到根元素上。
  • Icon.vue
<template>
  <i class="yl-icon">
    <font-awesome-icon v-bind="$props"/>
  </i>
</template>

<script setup lang="ts">
import type {FontAwesomeIconProps} from './types'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
defineOptions({
  name:'YlIcon',
  inheritAttrs:false
})
defineProps<FontAwesomeIconProps>()
</script>
  • types.ts
export type { FontAwesomeIconProps } from '@fortawesome/vue-fontawesome'

  • App.vue
import Icon from './components/Icon/Icon.vue'

(四)Icon组件功能完善:主题色和自定义颜色

node_modules\@fortawesome\vue-fontawesome\index.d.tsFontAwesomeIconProps接口添加自定义属性

  • index.d.ts
interface FontAwesomeIconProps {
//...
  type?: 'primary'| 'success'| 'warning'| 'danger'| 'info'
  color?: string
}

安装lodash实用工具库和类型定义文件

    npm install lodash-es --save
    npm install @types/lodash-es --save-dev

过滤掉不需要传递给 FontAwesomeIcon 组件的属性

  • omit 函数omit 是 lodash-es 库中的一个实用函数,用于从一个对象中移除指定的属性,并返回一个新的对象,该新对象不包含被移除的属性。
  • props:是通过 defineProps 定义的组件属性对象,它包含了父组件传递给 YlIcon 组件的所有属性。
  • ['type', 'color'] :是要从 props 对象中移除的属性名数组。
  • filteredProps:是调用 omit 函数后返回的新对象,它包含了 props 中除 type 和 color 之外的所有属性。
  • Icon.vue
<template>
  <i class="yl-icon" :class="{ [`yi-icon--${type}`]: type }" :style="custonStyles" v-bind="$attrs">
    <font-awesome-icon v-bind="filteredProps" />
  </i>
</template>
//...
import { computed } from 'vue'
import { omit } from 'lodash-es'
//..
const props = defineProps<FontAwesomeIconProps>()
const filteredProps = computed(() => omit(props, ['type', 'color']))
const custonStyles = computed(() => {
  return props.color ? { color: props.color } : {}
})
  • App.vue
const size=ref<any>('3x')

(五)为Button和Collapse添加图标

Button组件

  • Button/types.ts
export interface ButtonProps {
  //...
  icon?: string
  loading?: boolean
}
  • Button.vue
<button
//...
    :class="{
      //...
      'is-loading': loading,
    }"
    :disabled="disabled || loading"
    //...
    <Icon icon="spinner" spin v-if="loading"/>
    <Icon :icon="icon" v-if="icon"/>
</button>
  //...
  import Icon from '../Icon/Icon.vue'

image.png

Collapse组件

  • CollapseItem.vue
  import Icon from '../Icon/Icon.vue'
  <Icon icon="angle-right" class="header-angle"></Icon>