69 lines
1.5 KiB
Vue
69 lines
1.5 KiB
Vue
<script setup>
|
||
import { computed } from 'vue'
|
||
import { Loader } from '@lucide/vue'
|
||
|
||
/* ---------- props / emits / slots ---------- */
|
||
/**
|
||
* 按钮视觉变体
|
||
* @typedef {'default' | 'secondary' | 'outline' | 'ghost' | 'danger' | 'link'} ButtonType
|
||
*/
|
||
|
||
const props = defineProps({
|
||
/** 视觉变体 */
|
||
type: {
|
||
/** @type {ButtonType} */
|
||
type: String,
|
||
default: 'default',
|
||
validator: (value) =>
|
||
['default', 'secondary', 'outline', 'ghost', 'danger', 'link'].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>
|