Files
workspace/code/base-project/base-vue/packages/ao-design/src/button/index.tsx
T
2025-09-11 17:31:55 +08:00

80 lines
2.4 KiB
TypeScript

import type { PropType } from 'vue'
import { computed, defineComponent } from 'vue'
import { getPrefixCls } from '../_utils/getPrefixCls'
import Icon from '../icon'
export default defineComponent({
name: 'Button',
props: {
type: {
type: String as () => 'solid' | 'outline' | 'text' | 'dashed',
default: 'solid',
},
status: {
type: String as () => 'primary' | 'danger' | 'warning' | 'success' | 'default',
default: 'default',
},
disabled: { type: Boolean, default: false },
loading: { type: Boolean, default: false },
icon: { type: String, default: '' },
iconPosition: { type: String as () => 'left' | 'right', default: 'left' },
size: { type: String as () => 'small' | 'medium' | 'large', default: 'medium' },
block: { type: Boolean, default: false },
onClick: { type: Function as PropType<(event: MouseEvent) => void> }, // 注意这里不要加 ?
},
setup(props, { slots }) {
const prefixCls = getPrefixCls('btn')
const cls = computed(() => [
prefixCls,
`${prefixCls}-${props.type}`,
`${prefixCls}-status-${props.status}`,
`${prefixCls}-${props.size}`,
props.block && `${prefixCls}-block`,
])
const iconSize = computed(() => {
const map = { small: 14, medium: 16, large: 16 }
return map[props.size]
})
const hasContent = !!slots.default?.().length
return () => {
return (
<button
class={cls.value}
disabled={props.disabled || props.loading}
onClick={props.onClick}
>
{props.iconPosition === 'left' && (props.loading || props.icon) && (
<Icon
icon={props.loading ? 'mingcute:loading-line' : props.icon}
class={[
`${prefixCls}-icon-left`,
hasContent ? `${prefixCls}-icon-left-has-text` : '',
]}
spin={props.loading}
size={iconSize.value}
/>
)}
<span>
{slots.default?.()}
</span>
{props.iconPosition === 'right' && props.icon && (
<Icon
icon={props.icon}
class={[
`${prefixCls}-icon-right`,
hasContent ? `${prefixCls}-icon-right-has-text` : '',
]}
size={iconSize.value}
/>
)}
</button>
)
}
},
})