传递参数说明
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>
只有两个值是外部传入,其余绑定的值由内部控制
Number
<t-button :time="2000" @click="handleClick" /> <!-- 2秒内只能点击一次 -->
ButtonType
(字符串联合类型)'add' | 'import'| 'export'| 'delete'
'default' |'primary' |'success' | 'warning' |'danger' | 'info'
'default'
<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是一种状态,采用内部定义,与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)