161 lines
4.3 KiB
TypeScript
161 lines
4.3 KiB
TypeScript
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>
|
||
)
|
||
}
|
||
},
|
||
})
|