在前端开发中,组件库的使用能够极大地提高开发效率,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.ts的FontAwesomeIconProps接口添加自定义属性
- 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'
Collapse组件
- CollapseItem.vue
import Icon from '../Icon/Icon.vue'
<Icon icon="angle-right" class="header-angle"></Icon>