Files
workspace/code/base-project/base-vue/packages/ao-design/src/badge/index.tsx
T
2025-09-21 21:52:08 +08:00

161 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<number | string>,
},
minCount: {
type: [Number, String] as PropType<number | string>,
default: undefined,
},
maxCount: {
type: [Number, String] as PropType<number | string>,
},
showZero: {
type: Boolean,
default: false,
},
ribbonText: {
type: [String, Object, Function] as PropType<string | VNode | (() => 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<string, string> = {}
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<string, string> = {}
// 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 = <sup class={`${prefixCls}-dot`} style={supStyle}></sup>
}
else if (props.type === 'circle' && displayCount.value !== undefined) {
supNode = (
<sup class={`${prefixCls}-circle`} style={supStyle}>
{displayCount.value}
</sup>
)
}
else if (props.type === 'custom') {
supNode = (
<sup class={`${prefixCls}-custom`} style={supStyle}>
{slots.content?.()}
</sup>
)
}
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 = (
<sup class={`${prefixCls}-ribbon`} style={supStyle}>
<div class={`${prefixCls}-ribbon-text`} style={ribbonTextStyle}>
{renderRibbonText()}
</div>
<div class={`${prefixCls}-ribbon-corner`}></div>
</sup>
)
}
return (
<div class={[prefixCls, props.class]} style={{ ...props.style }}>
{slots.default?.()}
{supNode}
</div>
)
}
},
})