import type { PropType, VNode } from 'vue' import { computed, defineComponent } from 'vue' import { getPrefixCls } from '../_utils/getPrefixCls' export default defineComponent({ name: 'Badge', props: { type: { type: String as () => 'circle' | 'dot' | 'custom' | 'ribbon', default: 'circle', }, count: { type: [Number, String] as PropType, }, minCount: { type: [Number, String] as PropType, default: undefined, }, maxCount: { type: [Number, String] as PropType, }, showZero: { type: Boolean, default: false, }, ribbonText: { type: [String, Object, Function] as PropType VNode)>, default: '', }, offset: { type: Array as PropType<(string | number)[]>, default: undefined, }, color: { type: String, default: '', }, backgroundColor: { type: String, default: '', }, class: { type: [String, Array, Object], default: '', }, style: { type: Object, default: () => ({}), }, }, setup(props, { slots }) { const prefixCls = getPrefixCls('badge') const displayCount = computed(() => { if (props.type !== 'circle') return props.count let countNum = Number(props.count) const maxNum = props.maxCount != null ? Number(props.maxCount) : null const minNum = props.minCount != null ? Number(props.minCount) : null const isCountNumeric = Number.isFinite(countNum) const isMaxNumeric = maxNum !== null && Number.isFinite(maxNum) const isMinNumeric = minNum !== null && Number.isFinite(minNum) // 如果传了 minCount,showZero 不生效 if (!isMinNumeric && !props.showZero && countNum === 0) return undefined // 先处理 minCount if (isCountNumeric && isMinNumeric && countNum < (minNum as number)) { countNum = minNum as number } // 再处理 maxCount if (isCountNumeric && isMaxNumeric && countNum > (maxNum as number)) { return `${maxNum}+` } return countNum }) return () => { const supStyle: Record = {} if (props.offset && props.offset.length === 2) { const [x, y] = props.offset supStyle.top = typeof y === 'number' ? `${y}px` : y supStyle.right = typeof x === 'number' ? `${x}px` : x } // backgroundColor if (props.backgroundColor) { if (props.type === 'ribbon') { supStyle.backgroundColor = props.backgroundColor supStyle.color = props.backgroundColor } else { supStyle.color = props.backgroundColor } } const ribbonTextStyle: Record = {} // color if (props.color) { if (props.type === 'ribbon') { ribbonTextStyle.color = props.color } else { supStyle.color = props.color } } let supNode = null if (props.type === 'dot') { supNode = } else if (props.type === 'circle' && displayCount.value !== undefined) { supNode = ( {displayCount.value} ) } else if (props.type === 'custom') { supNode = ( {slots.content?.()} ) } else if (props.type === 'ribbon') { const renderRibbonText = () => { if (slots.ribbon) return slots.ribbon() if (typeof props.ribbonText === 'function') return props.ribbonText() return props.ribbonText } supNode = (
{renderRibbonText()}
) } return (
{slots.default?.()} {supNode}
) } }, })