78 lines
1.7 KiB
Vue
78 lines
1.7 KiB
Vue
<script setup>
|
||
import { computed } from 'vue'
|
||
import { Loader } from '@lucide/vue'
|
||
|
||
/* ---------- props / emits / slots ---------- */
|
||
/**
|
||
* 按钮视觉变体
|
||
* @typedef {'primary' | 'secondary' | 'outline' | 'ghost' | 'danger' | 'danger-outline' | 'link' | 'icon'} ButtonType
|
||
*/
|
||
|
||
const props = defineProps({
|
||
/** 视觉变体;icon 为工具条 / 面板头部动作位的正方形描边图标按钮 */
|
||
type: {
|
||
/** @type {ButtonType} */
|
||
type: String,
|
||
default: 'primary',
|
||
validator: (value) =>
|
||
[
|
||
'primary',
|
||
'secondary',
|
||
'outline',
|
||
'ghost',
|
||
'danger',
|
||
'danger-outline',
|
||
'link',
|
||
'icon',
|
||
].includes(value),
|
||
},
|
||
/** 禁用态 */
|
||
disabled: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
/** 加载态 */
|
||
loading: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
/** 通栏(占满整行宽度) */
|
||
block: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
/** 原生 type:button | submit | reset,用于表单提交 / 重置按钮 */
|
||
htmlType: {
|
||
type: String,
|
||
default: 'button',
|
||
validator: (value) => ['button', 'submit', 'reset'].includes(value),
|
||
},
|
||
})
|
||
|
||
/* ---------- 公共 computed ---------- */
|
||
const isDisabled = computed(() => props.disabled || props.loading)
|
||
|
||
const classes = computed(() => [
|
||
'button',
|
||
`button-${props.type}`,
|
||
props.block ? 'button-block' : '',
|
||
props.loading ? 'button-loading' : '',
|
||
])
|
||
</script>
|
||
|
||
<template>
|
||
<button
|
||
:type="htmlType"
|
||
:class="classes"
|
||
:disabled="isDisabled"
|
||
:aria-busy="loading || undefined"
|
||
>
|
||
<Loader v-if="loading" class="button-spinner" aria-hidden="true" />
|
||
<slot />
|
||
</button>
|
||
</template>
|
||
|
||
<style scoped lang="scss">
|
||
@use './index.scss';
|
||
</style>
|