当前位置: 首页 > article >正文

elementPlus-button组件二次封装

elementPlus-button组件二次封装

目录

  • 传递参数说明

    • 1.time

    • 2.type

    • 3.icon

  • 二次封装了什么

    • 属性透传

    • 预设类型

    • 预设映射

    • 节流约束

    • loading联动

  • 源代码

传递参数说明

  <el-button
    ref="buttonRef"
    v-bind="$attrs"
    :type="computedProps.type"
    :icon="computedProps.icon"
    :disabled="isDisabled"
    @click="handleClick"
  >
    <slot />
  </el-button>

只有两个值是外部传入,其余绑定的值由内部控制

1.time
  • 类型:Number
  • 默认值:1000(毫秒)
  • 用途:控制按钮点击的节流时间间隔
  • 使用示例:
    <t-button :time="2000" @click="handleClick" />  <!-- 2秒内只能点击一次 -->
    
2.type
  • 类型:ButtonType(字符串联合类型)
  • 可选值:
  • 预设业务类型:'add' | 'import'| 'export'| 'delete'
  • 基础类型:'default' |'primary' |'success' | 'warning' |'danger' | 'info'
  • 默认值:'default'
  • 用途:设置按钮的类型和样式
  • 使用示例:
    <t-button type="add" />  <!-- 新增按钮:主色系 + 加号图标 -->
    <t-button type="import" />  <!-- 导入按钮:默认样式 + 上传图标 -->
    <t-button type="primary" />  <!-- 主要按钮 -->
    
3.icon
  • 类型:String
  • 默认值:‘’
  • 作用:设置按钮的图标
  • 说明:支持Element Plus 的所有图标名称
  • 示例:icon=“Edit”
    <t-button icon="search" /> 
    

二次封装了什么

属性透传

该绑定保留了elementPlus原生按钮的所有功能传参,自动透传未被声明的 props。

<el-button v-bind="$attrs" ...>
预设类型

这样我们在给组件传参的时候可以看到vscode展示的预设类型提示

在基础的类型上添加了业务类型

type ButtonType =
  | 'add'
  | 'import'
  | 'export'
  | 'delete'
  | 'default'
  | 'primary'
  | 'success'
  | 'warning'
  | 'danger'
  | 'info'
  
预设映射

将原有的if-else结构优化成map映射结构,减少代码冗余,提高开发效率

这样通过传入的业务类型就可以绑定type和icon,并且保留组件原有的icon传入设置

// 类型与图标映射
const TYPE_ICON_MAP = {
  add: { type: 'primary', icon: 'CirclePlus' },
  import: { type: 'default', icon: 'Upload' },
  export: { type: 'default', icon: 'Download' },
  delete: { type: 'danger', icon: 'Delete' }
} as const

// 根据 props.type 与 props.icon 计算出最终类型与图标
const computedProps = computed(() => {
  const fallback = { type: props.type, icon: props.icon || '' }
  const entry = TYPE_ICON_MAP[props.type] || fallback
  const icon = innerLoading.value ? 'Loading' : (TYPE_ICON_MAP[props.type] ? entry.icon : props.icon || '')
  return {
    type: entry.type,
    icon
  }
})

节流约束

通过接收的time来进行节流限制,并且在节流触发时会激活内置的loading状态,围绕这个loading状态来展开节流,之后将点击事件暴露给父组件并移除焦点

const handleClick = (event: MouseEvent) => {
  if (innerLoading.value) return
  if (props.time) {
    innerLoading.value = true
    setTimeout(() => {
      innerLoading.value = false
    }, props.time)
  }
  emits('click', event)
  buttonRef.value?.ref?.blur()
}

节流过程中会持续loading和disabled

const attrs = useAttrs()
const isDisabled = computed(() => {
  return innerLoading.value || attrs.disabled
})
loading联动

这里的loading是一种状态,采用内部定义,与disabled、节流函数和loading图标联动

在节流过程中自动触发loading状态,loading状态会将button设置成disabled状态并添加loading的icon图标。

const innerLoading = ref(false)

const computedProps = computed(() => {
  //省略
  const icon = innerLoading.value ? 'Loading' : (TYPE_ICON_MAP[props.type] ? entry.icon : props.icon || '')
  //省略
})

const buttonRef = ref<any>(null)

const handleClick = (event: MouseEvent) => {
  if (innerLoading.value) return
  if (props.time) {
    innerLoading.value = true //loading
    setTimeout(() => {
      innerLoading.value = false //loading
    }, props.time)
  }
  emits('click', event)
  buttonRef.value?.ref?.blur()
}

const attrs = useAttrs()
const isDisabled = computed(() => innerLoading.value || attrs.disabled)

源代码

<template>
  <el-button
    ref="buttonRef"
    v-bind="$attrs"
    :type="computedProps.type"
    :icon="computedProps.icon"
    :disabled="isDisabled"
    @click="handleClick"
  >
    <slot />
  </el-button>
</template>

<script setup lang="ts" name="TButton">
import { ref, computed, useAttrs } from 'vue'
import type { PropType } from 'vue'

type ButtonType =
  | 'add'
  | 'import'
  | 'export'
  | 'delete'
  | 'default'
  | 'primary'
  | 'success'
  | 'warning'
  | 'danger'
  | 'info'

// 内部loading状态
const innerLoading = ref(false)

const props = defineProps({
  time: {
    type: Number,
    default: undefined
  },
  type: {
    type: String as PropType<ButtonType>,
    default: 'default'
  },
  icon: {
    type: String,
    default: ''
  }
})

// 事件
const emits = defineEmits(['click'])

// 类型与图标映射
const TYPE_ICON_MAP = {
  add: { type: 'primary', icon: 'CirclePlus' },
  import: { type: 'default', icon: 'Upload' },
  export: { type: 'default', icon: 'Download' },
  delete: { type: 'danger', icon: 'Delete' }
} as const

// 根据 props.type 与 props.icon 计算出最终类型与图标
const computedProps = computed(() => {
  const fallback = { type: props.type, icon: props.icon || '' }
  const entry = TYPE_ICON_MAP[props.type] || fallback
  const icon = innerLoading.value ? 'Loading' : (TYPE_ICON_MAP[props.type] ? entry.icon : props.icon || '')
  return {
    type: entry.type,
    icon
  }
})

const buttonRef = ref<any>(null)

const handleClick = (event: MouseEvent) => {
  if (innerLoading.value) return
  if (props.time) {
    innerLoading.value = true
    setTimeout(() => {
      innerLoading.value = false
    }, props.time)
  }
  emits('click', event)
  buttonRef.value?.ref?.blur()
}

const attrs = useAttrs()
const isDisabled = computed(() => innerLoading.value || attrs.disabled)
</script>



http://www.kler.cn/a/517637.html

相关文章:

  • 工业数据分析:解锁工厂数字化的潜力
  • 非根目录部署 nextjs 项目,资源文件 请求404 的问题
  • 写一个存储“网站”的网站前的分析
  • Synology 群辉NAS安装(4)docker-compose
  • 【开源免费】基于Vue和SpringBoot的医院资源管理系统(附论文)
  • 【算法】快速排序1
  • LlamaV-o1:重塑大型语言模型中的逐步视觉推理
  • 最长递增——蓝桥杯
  • javaSE.类的继承
  • 2025.1.24总结
  • TMC2208替代A4988
  • 第38周:猫狗识别 (Tensorflow实战第八周)
  • Flink读写Kafka(Table API)
  • 分享14分数据分析相关ChatGPT提示词
  • 如何设计浪漫风格的壁纸
  • 低代码开发:效率革命与市场机遇
  • YOLOv10-1.1部分代码阅读笔记-model.py
  • C++入门14——set与map的使用
  • c#实现重启Explorer.exe并且启动某个命令
  • CSS 提示工具:优化网页设计,提升用户体验
  • 关于BAR(PCIE BAR或AXI BAR)的解释
  • 广西螺蛳粉:舌尖上的美食传奇
  • 【豆包MarsCode 蛇年编程大作战】蛇形烟花
  • MATLAB遗传算法求解函数最大值
  • 简约的单用户看板待办事项应用Tellor
  • 无人机核心项目开发系列:从设计到实现的完整解析