首页
/ Ant Design Badge 混用实战:count、dot 与 status、color 的组合规则与源码解析

Ant Design Badge 混用实战:count、dot 与 status、color 的组合规则与源码解析

2026-09-06 13:38:40作者:龚格成

本篇以 Ant Design 中 Badge 的「混用」示例(mix demo)为核心,系统讲解 countdotstatuscolor 四类属性如何组合生效。读完你会掌握:四类属性在组合场景下的优先级与显示规则、showZero / overflowCount 等边界行为的源码依据,以及自定义颜色、状态色在样式层的具体落地方式,可直接用于处理“数字、红点、状态点”混用的实际业务场景。

一、示例定位:mix 演示在解决什么问题

Badge 组件文档(index.zh-CN.md)将 mix.tsx 标注为「各种混用的情况」的 debug 演示,其说明文档 mix.md 的定义是:

测试 count status color dot 共用的情况。(Using count/dot with custom status/color.)

也就是说,单独使用 count(数字徽标)、dot(小红点)、status(预设状态点)、color(自定义颜色)各自都有独立示例,而 mix 示例专门回答一个组合问题:当这些属性同时出现时,谁生效、样式如何叠加、边界值(0、封顶)如何表现。以下完整继承该示例代码并逐段拆解。

二、mix 示例完整代码与组合矩阵

mix.tsx 的完整实现(两组 Space 分别验证「有内容包裹」与「独立/零值」两类场景):

import React from 'react';
import { Avatar, Badge, Space } from 'antd';

const App: React.FC = () => (
  <Space size="medium" wrap>
    <Space size="medium" wrap>
      {/* 第一组:count / dot 分别与 status / color 混用,包裹子元素 */}
      <Badge count={5} status="success">
        <Avatar shape="square" size="large" />
      </Badge>
      <Badge count={5} status="warning">
        <Avatar shape="square" size="large" />
      </Badge>
      <Badge count={5} color="blue">
        <Avatar shape="square" size="large" />
      </Badge>
      <Badge count={5} color="#fa541c">
        <Avatar shape="square" size="large" />
      </Badge>
      <Badge dot status="success">
        <Avatar shape="square" size="large" />
      </Badge>
      <Badge dot status="warning">
        <Avatar shape="square" size="large" />
      </Badge>
      <Badge dot status="processing">
        <Avatar shape="square" size="large" />
      </Badge>
      <Badge dot color="blue">
        <Avatar shape="square" size="large" />
      </Badge>
      <Badge dot color="#fa541c">
        <Avatar shape="square" size="large" />
      </Badge>
    </Space>

    {/* 第二组:零值与 showZero 边界场景 */}
    <Space size="medium" wrap>
      <Badge count={0} showZero />
      <Badge count={0} showZero color="blue" />
      <Badge count={0} showZero color="#f0f" />
      <Badge count={0} showZero>
        <Avatar shape="square" size="large" />
      </Badge>
      <Badge count={0} showZero color="blue">
        <Avatar shape="square" size="large" />
      </Badge>
      <Badge count={0} color="#f0f" />
      <Badge status="success" text={0} showZero />
      <Badge status="warning" text={0} />
    </Space>
  </Space>
);

export default App;

从代码可以归纳出示例覆盖的完整组合矩阵:

组合 示例写法 预期表现
数字 + 预设状态色 count={5} status="success" 数字气泡,背景换成对应状态色
数字 + 预设色 count={5} color="blue" 数字气泡,背景为预设色板中的 blue
数字 + 自定义色 count={5} color="#fa541c" 数字气泡,背景为任意色值
小红点 + 预设状态色 dot status="processing" 小圆点,状态色;processing 还带脉冲动画
小红点 + 预设/自定义色 dot color="blue" / dot color="#fa541c" 小圆点,指定颜色
零值 + showZero count={0} showZero 显示 “0” 气泡
零值 + 颜色,无 showZero count={0} color="#f0f" 整体隐藏
状态点 + 文本零值 status="success" text={0} showZero / status="warning" text={0} 前者显示 “0” 文本,后者仅显示圆点

三、组合行为的源码判定链:四个关键变量

上述所有表现都由 Badge.tsx 中的一条判定链决定。逐段对照源码:

3.1 封顶与零值判定

// components/badge/Badge.tsx#L111-L122
const numberedDisplayCount = (
  (count as number) > (overflowCount as number) ? `${overflowCount}+` : count
) as string | number | null;

const isZero =
  numberedDisplayCount === '0' || numberedDisplayCount === 0 || text === '0' || text === 0;

const ignoreCount = count === null || (isZero && !showZero);

const hasStatus = (isNonNullable(status) || isNonNullable(color)) && ignoreCount;

四个变量构成核心逻辑:

  1. numberedDisplayCountcount 超过 overflowCount(默认 99,见 BadgeProps 解构默认值)时显示为 99+,这就是文档 API 表中「大于 overflowCount 时显示为 ${overflowCount}+」的实现。
  2. isZero:数字为 0 或文本为 0 都算零值——注意 text 也会参与判定,这正是 mix 第二组 text={0} 场景能被统一处理的原因。
  3. ignoreCount:没有 count,或零值且未开 showZero 时,数字被忽略。
  4. hasStatus:只有 statuscolor 存在且数字被忽略时,才启用「状态点」布局(行内圆点 + 可选文本)。

hasStatus 这个条件值得强调:它决定了 <Badge status="success" />(无 children、无 count)渲染为行内状态点,而 <Badge count={5} status="success"> 渲染为角标数字——同样的 status 属性,两种渲染形态。

3.2 dot 的优先级:dot 与 count 同时设置

// components/badge/Badge.tsx#L161-L163
const showAsDot = dot && !isZero;
const mergedCount = showAsDot ? '' : numberedDisplayCount;

dotcount 同时传入时,dot 无条件优先mergedCount 被置空,数字不会显示。mix 示例中第一组虽然都是 dot status=...,但这条规则意味着写 <Badge dot count={5}> 只会得到红点。同时 showAsDot = dot && !isZero 说明零值时 dot 也不渲染(mergedCount 为空且不满足显示条件时整个徽标隐藏,见下文 isHidden)。

3.3 status/color 与 count 如何“叠加”而非“互斥”

mix 示例的关键点在于:count={5} status="success" 不是“状态点取代数字”,而是状态色改变数字气泡的背景。这一点体现在类名合并处:

// components/badge/Badge.tsx#L277-L285
const scrollNumberCls = clsx(mergedClassNames.indicator, {
  [`${prefixCls}-dot`]: isDot,
  [`${prefixCls}-count`]: !isDot,
  [`${prefixCls}-count-sm`]: size === 'small',
  [`${prefixCls}-multiple-words`]:
    !isDot && displayCount && displayCount.toString().length > 1,
  [`${prefixCls}-status-${status}`]: !!status,
  [`${prefixCls}-color-${color}`]: isInternalColor,
});

即:数字气泡(-count)与 dot(-dot)之外,-status-{status}-color-{color} 类名会追加到同一个指示器元素上。根节点则通过 hasStatus 判断是否加 -status 类切换为行内状态布局(Badge.tsx#L225-L238)。这就是「混用」的准确含义:count/dot 决定形态,status/color 决定颜色

3.4 隐藏逻辑与零值场景

// components/badge/Badge.tsx#L165-L168
const isHidden = useMemo(() => {
  const isEmpty = !isReactRenderable(mergedCount) && !isReactRenderable(text);
  return (isEmpty || (isZero && !showZero)) && !showAsDot;
}, [mergedCount, isZero, showZero, showAsDot, text]);

对应 mix 第二组的表现:

  • count={0} showZeroisZero 为真但 showZero 为真 → 不隐藏,显示 “0”;
  • count={0} color="#f0f"(无 showZero):isZero && !showZero → 整体 isHidden,连颜色一起消失;
  • status="success" text={0} showZero:走独立状态点分支,showStatusTextNode = text === 0 ? showZero : ...Badge.tsx#L197)决定 “0” 文本是否显示;而 status="warning" text={0} 因未开 showZero 只显示圆点。

源码中还用 countRef / displayCountRef 缓存上一次非隐藏状态的值(Badge.tsx#L170-L182),保证隐藏/出现动画(CSSMotion)执行过程中数字不闪变。

四、status 与 color 的两种取色路径

mix 示例同时使用了预设色("blue")与自定义色("#fa541c"),两者在实现上是不同路径:

// components/badge/Badge.tsx#L209-L223
const isInternalColor = isPresetColor(color, false);
// ...
if (color && !isInternalColor) {
  statusStyle.color = color;
  statusStyle.background = color;
}
  • 预设色路径isPresetColor(定义于 colors.ts)判定 color 是否在预设色板内。若在,仅添加 -color-{key} 类名,背景色由样式层统一生成——见 style/index.ts#L166-L176 中的 genPresetColor,它为每个预设色生成 .ant-badge .ant-badge-color-{key} { background: <深色> } 规则,从而自动适配暗色主题;
  • 自定义色路径:非预设色则直接以行内 background / color 样式覆盖(独立状态点分支见 Badge.tsx#L219-L223,包裹分支见 Badge.tsx#L292-L295)。

status 的五个取值 success | processing | default | error | warning(与 PresetStatusColors 一致)由 style/index.ts#L266-L302 映射到语义色 token:-status-success → colorSuccess-status-warning → colorWarning-status-error → colorError-status-default → colorTextPlaceholderprocessing 特殊,额外通过 ::after 伪元素播放 antStatusProcessing 扩散动画(style/index.ts#L269-L291),这就是 mix 示例中 dot status="processing" 圆点会“呼吸”的原因。

五、样式层:数字气泡、dot 与动画的落地

结合 style/index.ts,mix 示例中每种形态的视觉来源如下:

  • 数字气泡 -countmin-width / heightindicatorHeight token 决定,背景为 badgeColor(默认 colorError,即红色),配 box-shadow: 0 0 0 {lineWidth} {colorBorderBg} 形成描边感,见 style/index.ts#L186-L213size="small" 时追加 -count-sm 切换到小号 token;多位数(含 99+)追加 -multiple-words 增加水平内边距。
  • 小圆点 -dot:宽高为 dotSizeborderRadius: 100%,同样继承 status/color 类名改色。
  • 定位-count-dot 与自定义组件统一 position: absolute; top: 0; insetInlineEnd: 0; transform: translate(50%, -50%),锚定在子元素右上角,RTL 下镜像为 translate(-50%, -50%),见 style/index.ts#L239-L251L369-L375
  • 缩放动画:Badge 包裹 CSSMotion(motionName 为 badge-zoom,见 Badge.tsx#L263-L268),出现/消失播放 antZoomBadgeIn/Out 关键帧;无子元素的独立形态(-not-a-wrapper)使用另一套以自身为中心的 antNoWrapperZoomBadgeIn/Outstyle/index.ts#L322-L346),这解释了 mix 第二组“裸 Badge”动画与包裹形态的差异。
  • 数字滚动:数字内容实际由 ScrollNumber.tsx 渲染;当数值为整数时,逐位拆分为 SingleNumber.tsx 单元,通过 translateY 位移实现滚动计数动画,并有 1 秒超时兜底(onTransitionEnd 回写,SingleNumber.tsx#L50-L59)。非整数(如 99.5+ 这类自定义 count)不拆分、无滚动。

六、Badge 完整参数速查

结合 index.zh-CN.md 的 API 表与 BadgeProps 源码类型,mix 场景相关参数如下:

参数 说明 类型 默认值
count 展示的数字,大于 overflowCount 时显示为 ${overflowCount}+,为 0 时隐藏 ReactNode -
dot 不展示数字,只有一个小红点 boolean false
status 设置 Badge 为状态点 success | processing | default | error | warning -
color 自定义小圆点(含数字气泡)的颜色,支持预设色与任意色值 string -
showZero 当数值为 0 时,是否展示 Badge boolean false
overflowCount 展示封顶的数字值 number 99
offset 设置指示器的位置偏移 [number, number] -
size 设置小圆点的大小(设置 count 前提下有效) medium | small medium
text 设置状态点的文本(设置 status 前提下有效) ReactNode -
title 鼠标悬停提示,null / false 时移除原生 tooltip string | null | false -

其中 count 的实际类型为 ReactNodeBadge.tsx#L36),传 React 元素时走 displayNode 自定义渲染路径(Badge.tsx#L203-L207);color 类型为 LiteralUnion<PresetColorKey>,即预设色之外允许任意字符串(Badge.tsx#L48)。

七、实践要点与常见误区

  1. count/dot 与 status/color 是正交的:前者选形态(数字 vs 小圆点),后者选颜色。想让“未读消息数”显示为绿色成功态,就写 count={n} status="success",而不是换成 Badge status 独立形态。
  2. dot 会压制 count:两者同时设置时只显示圆点(showAsDot 逻辑),不需要担心数字与圆点同时渲染。
  3. 0 值必须显式 showZero:无论数字还是状态文本,0 值默认全部隐藏;mix 第二组 count={0} color="#f0f"(无 showZero)会整体消失,是排查“徽标不见了”时的第一检查项。
  4. 预设色优先color="blue" 走 CSS 类路径可自动适配暗色主题,color="#fa541c" 走行内样式则是固定值,主题切换时不会变化。
  5. 动画一致性有源码保障:隐藏/出现过程中数字与 dot 形态通过 ref 缓存维持,不会出现退出动画期间内容跳变(Badge.tsx#L170-L188)。

mix 示例的所有行为都有对应测试覆盖:demo.test.tsx 对所有 demo(含 mix)执行渲染快照测试,index.test.tsx 覆盖组件属性行为,a11y.test.ts 验证无障碍属性。修改或封装 Badge 相关功能时,可运行这些用例确认行为是否与源码预期一致。

小结

mix 示例的核心价值在于它把 Badge 的四个“着色/形态”属性压在同一段代码里,暴露出 Ant Design 的混用规则:count/dot 决定指示器形态,status/color 作为类名或行内样式叠加其上改色;0 值由 showZero 统一治理;hasStatus 分支决定独立状态点布局何时启用。理解了 Badge.tsxisZero → ignoreCount → hasStatus → showAsDot 这条判定链,再配合 style/index.ts 的类名与 token 映射,即可准确预判任意组合的渲染结果,并据此编写可复制、可运行的业务代码。

登录后查看全文
热门项目推荐
相关项目推荐