Element-Plus源码分析--button组件

引言

再对Elements-Plus的设计框架有了初步了解过后 也通过对最基础的组件elIcon的设计源码进行分析之后,理解了其中组件设计的流程。那么再继续提高组件的复杂度继续看看elButton组建的实现。 组件目录如下

js 复制代码
├── packages
│   ├── components
│   │   ├── button
│   │   │   ├── __tests__       # 测试目录
│   │   │   ├── src             # 组件入口目录
│   │   │   │   ├── button-custom.ts   # 自定义类型,方法
│   │   │   │   └── button-group.ts    # button-group组件属性与ts类型
│   │   │   │   └── button-group.vue   # button-group组件模板内容
│   │   │   │   └── button.ts       #组件属性与 TS 类型
│   │   │   │   └── button.vue      #组件模板内容
│   │   │   │   └── constants.ts    #常量申明
│   │   │   │   └── instance.ts     #button&button-group的组件类型注册
│   │   │   │   └── use-button.ts   #组件hook
│   │   │   ├── style           # 组件样式目录
│   │   │   └── index.ts        # 组件入口文件
│   │   └── package.json

 

先从基本的button.ts文件开始来看,引入方法、类型

js 复制代码
import { useSizeProp } from '@element-plus/hooks' //引入字符串枚举类型
import { buildProps, definePropType, iconPropType } from '@element-plus/utils' //props优化工具类,组件类型
import { Loading } from '@element-plus/icons-vue'
import type { Component, ExtractPropTypes } from 'vue' //vue提供的props转换方法类型,component类型

定义需要的类型

js 复制代码
export const buttonProps = buildProps({
//
***
  ***
  *****
  
  loadingIcon: {
    type: iconPropType,
    default: () => Loading,
  },//loading图标接收组件类型
  
  ****
  *****
  //是否在汉字之间插入空格
    autoInsertSpace: {
    type: Boolean,
    default: undefined,
  }, //APi中为注明的属性
   /**
   * @description custom element tag  自定义的标签可传入组件 v2.3.4 以上版本新增
   */
  tag: {
    type: definePropType<string | Component>([String, Object]),
    default: 'button',
  },
})

抛出事件类型,优化之后的props属性

js 复制代码
export const buttonEmits = {
  click: (evt: MouseEvent) => evt instanceof MouseEvent,
}
export type ButtonProps = ExtractPropTypes<typeof buttonProps>
export type ButtonEmits = typeof buttonEmits
export type ButtonType = ButtonProps['type']
export type ButtonNativeType = ButtonProps['nativeType']

export interface ButtonConfigContext {
  autoInsertSpace?: boolean
}
button.vue文件
js 复制代码
//动态组件 默认使用button    2.3.4 以上版本新增 tag组件模式 自定义原型标签
<component :is="tag" ref="_ref" v-bind="_props" :class="buttonKls" :style="buttonStyle" @click="handleClick">

loading插槽

icon插槽

默认内容插槽

自定义内容插槽
****

</component>
const { _ref, _size, _type, _disabled, _props, shouldAddSpace, handleClick } =
  useButton(props, emit)
引入自定义事件,
props内容

const ns = useNamespace('button') 使用EBM 定义类
//根据状态设备不同的类名
const buttonKls = computed(() => [
  ns.b(),
  ns.m(_type.value),
  ns.m(_size.value),
  ns.is('disabled', _disabled.value),
  ns.is('loading', props.loading),
  ns.is('plain', props.plain),
  ns.is('round', props.round),
  ns.is('circle', props.circle),
  ns.is('text', props.text),
  ns.is('link', props.link),
  ns.is('has-bg', props.bg),
])
//使用vue3的defineExpose宏 抛出属性,方法
defineExpose({
  /** @description button html element */
  ref: _ref,
  /** @description button size */
  size: _size,
  /** @description button type */
  type: _type,
  /** @description button disabled */
  disabled: _disabled,
  /** @description whether adding space */
  shouldAddSpace,
})

button-group.ts定义button模式下的类型说明

button-group.vue 定义一个个插槽 使用ts定义的属性设置组件接收的prorps,provide 抛出buttonGroup的属性buttonGroupContextKey作为唯一键值

js 复制代码
provide(
  buttonGroupContextKey,
  reactive({
    size: toRef(props, 'size'),
    type: toRef(props, 'type'),
  })
)

那么申明 buttonGroupContextKey 用到的 type(InjectionKey)是什么? InjectionKey 是 Vue 3 组合式 API 中用于依赖注入的键类型,继承自 JavaScript 的 Symbol 类型。它通过类型断言确保 provideinject 函数中使用的键具有明确的类型安全性,主要用于组件间的数据传递; buttonGroupContextKey 的定义在 button/constants.ts的文件中有提到。

instance.ts文件

引入组件并抛出组件实例类型

js 复制代码
import type Button from './button.vue'
import type ButtonGroup from './button-group.vue'

export type ButtonInstance = InstanceType<typeof Button> & unknown
export type ButtonGroupInstance = InstanceType<typeof ButtonGroup> & unknown

最后需要在 button/index.ts 目录文件中定义 Button 组件的出口内容。

js 复制代码
// *****
 *****代码块
export const ElButton: SFCWithInstall<typeof Button> & {
  ButtonGroup: typeof ButtonGroup
} = withInstall(Button, {
  ButtonGroup,
})
export const ElButtonGroup: SFCWithInstall<typeof ButtonGroup> =
  withNoopInstall(ButtonGroup)
export default ElButton

export * from './src/button'
export * from './src/constants'
export type { ButtonInstance, ButtonGroupInstance } from './src/instance'
相关推荐
Felicity_Gao1 小时前
uni-app VOD 与 COS 选型、开发笔记
前端·笔记·uni-app
我狸才不是赔钱货3 小时前
前端技术栈全景图:从HTML到现代框架的演进之路
前端·html
百花~3 小时前
前端三剑客之一 HTML~
前端·html
lang201509284 小时前
Spring远程调用与Web服务全解析
java·前端·spring
listhi5206 小时前
利用React Hooks简化状态管理
前端·javascript·react.js
一点一木6 小时前
🚀 2025 年 10 月 GitHub 十大热门项目排行榜 🔥
前端·人工智能·github
华仔啊6 小时前
这个Vue3旋转菜单组件让项目颜值提升200%!支持多种主题,拿来即用
前端·javascript·css
非凡ghost7 小时前
Adobe Lightroom安卓版(手机调色软件)绿色版
前端·windows·adobe·智能手机·软件需求
BestAns7 小时前
Postman 平替?这款轻量接口测试工具,本地运行 + 批量回归超实用!
前端
专注前端30年8 小时前
Webpack进阶玩法全解析(性能优化+高级配置)
前端·webpack·性能优化