跳到主要内容

Badge 徽标

图标右上角的圆形徽标数字

基本使用
43
90
独立使用
43
22
99+
封顶数字,超过 overflowCount 的会显示为 overflowCount+,默认的 overflowCount 为 99。
10+
99+
999+
可以设置有数字徽标的大小
5
5
自定义位置偏移
90
基本使用
收起源代码
import React from 'react'
import { Badge, Space } from '@dance-ui/ui'

export default () => (
<Space direction="vertical">
基本使用
<Space gap="large">
<Badge color="red" count={43}>
<div
style={{
height: '40px',
width: '40px',
backgroundColor: '#BFBFBF',
borderRadius: '10px',
}}></div>
</Badge>
<Badge color="red" count={90}>
<div
style={{
height: '40px',
width: '40px',
backgroundColor: '#BFBFBF',
borderRadius: '10px',
}}></div>
</Badge>
</Space>
独立使用
<Space>
<Badge color="red" count={43}></Badge>
<Badge color="#faad14" count={22}></Badge>
<Badge color="rgb(82, 196, 26)" count={100} overflowCount={99}></Badge>
</Space>
封顶数字,超过 overflowCount 的会显示为 overflowCount+,默认的 overflowCount 为 99。
<Space gap="large">
<Badge color="red" count={43} overflowCount={10}>
<div
style={{
height: '40px',
width: '40px',
backgroundColor: '#BFBFBF',
borderRadius: '10px',
}}></div>
</Badge>
<Badge color="red" count={100} overflowCount={99}>
<div
style={{
height: '40px',
width: '40px',
backgroundColor: '#BFBFBF',
borderRadius: '10px',
}}></div>
</Badge>
<Badge color="red" count={1000} overflowCount={999}>
<div
style={{
height: '40px',
width: '40px',
backgroundColor: '#BFBFBF',
borderRadius: '10px',
}}></div>
</Badge>
</Space>
可以设置有数字徽标的大小
<Space gap="large">
<Badge color="red" count={5}>
<div
style={{
height: '40px',
width: '40px',
backgroundColor: '#BFBFBF',
borderRadius: '10px',
}}></div>
</Badge>
<Badge color="red" count={5} size="small">
<div
style={{
height: '40px',
width: '40px',
backgroundColor: '#BFBFBF',
borderRadius: '10px',
}}></div>
</Badge>
</Space>
自定义位置偏移
<Space gap="large">
<Badge color="red" count={90} offset={[10, -10]}>
<div
style={{
height: '40px',
width: '40px',
backgroundColor: '#BFBFBF',
borderRadius: '10px',
}}></div>
</Badge>
</Space>
</Space>
)

组件源码

组件源码
import classNames from 'classnames'
import React from 'react'

export type BadgeProps = {
/** 自定义小圆点的颜色 */
color?: string
/** 展示的数字,大于 overflowCount 时显示为 ${overflowCount}+,为 0 时隐藏 */
count?: number
/** 设置状态点的位置偏移正值为右/上 */
offset?: [number, number]
/** 展示封顶的数字值 */
overflowCount?: number
/** 当数值为 0 时,是否展示 Badge */
showZero?: boolean
/** 在设置了 count 的前提下有效,设置小圆点的大小 */
size?: 'default' | 'small'
/** 设置鼠标放在状态点上时显示的文字 */
title?: string
/** 组件额外的 CSS className */
className?: string
/** 组件额外的 CSS style */
style?: React.CSSProperties
/** 组件额外的 子节点 */
children?: any
}

const sizeStyle = {
default: 'h-5 w-5 text-xs',
small: 'h-4 w-4 text-xs',
}

const Badge = (props: BadgeProps): JSX.Element => {
const { color, count, offset, overflowCount, showZero, title, className, children, style } = props

let { size } = props
if (!count) {
size = 'default'
}
/** 最小数字 -1 */
let minNum: number = 0
if (showZero) {
minNum = -1
}

const computedCount = (): number | string => {
if (count && count > minNum) {
if (overflowCount) {
if (count > overflowCount) {
return `${overflowCount}+`
} else {
return count
}
} else {
return count
}
} else {
return ''
}
}

const countStyle = (): React.CSSProperties => {
const length: number = String(computedCount()).length
if (length === 1) {
return {
borderRadius: '50%',
}
} else {
if (size === 'default') {
return {
width: `${length * 0.5 + 0.75}rem`,
borderRadius: '20px',
}
} else {
return {
width: `${length * 0.4 + 0.75}rem`,
borderRadius: '20px',
}
}
}
}

const countRight = (): number => {
const length: number = String(computedCount()).length
if (length === 1) {
if (offset) {
return size === 'default' ? -offset[0] - 10 : -offset[0] - 8
} else {
return size === 'default' ? -10 : -8
}
} else {
if (offset) {
return size === 'default' ? -offset[0] - (length * 0.5 + 0.75) * 8 : -offset[0] - (length * 0.4 + 0.75) * 8
} else {
return size === 'default' ? -(length * 0.5 + 0.75) * 8 : -(length * 0.4 + 0.75) * 8
}
}
}

const countTop = (): number => {
if (offset) {
return size === 'default' ? -offset[1] - 10 : -offset[1] - 8
} else {
return size === 'default' ? -10 : -6
}
}

const BadgeNode = React.Children.map(children, (c) => {
return React.cloneElement(
c,
{ ...children.props, className: 'relative' },
<div style={style}>
{children?.props?.children}
<div
className={classNames(
'absolute box-border flex items-center justify-center border text-white transition focus:outline-none',
sizeStyle[size ?? 'default'],
className,
)}
style={{
right: countRight(),
top: countTop(),
backgroundColor: color,
...countStyle(),
}}
title={title}>
{computedCount()}
</div>
</div>,
)
})
if (children) {
return BadgeNode
} else {
return (
<div style={style}>
<div
className={classNames(
'box-border flex items-center justify-center border text-white transition focus:outline-none',
sizeStyle[size ?? 'default'],
className,
)}
style={{
right: countRight(),
top: countTop(),
backgroundColor: color,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
...countStyle(),
}}
title={title}>
{computedCount()}
</div>
</div>
)
}
}

Badge.defaultProps = {
color: 'red',
size: 'default',
offset: [0, 0],
overflowCount: 99,
showZero: false,
}

export default Badge