首页
/ Ant Design Image 占位符 placeholder 深入实践:水彩水墨动画、进度条与自定义节点

Ant Design Image 占位符 placeholder 深入实践:水彩水墨动画、进度条与自定义节点

2026-09-08 00:00:10作者:齐冠琰

本篇技术指南聚焦 Ant Design Image 组件的 placeholder 属性,结合官方 Demo 与仓库源码,系统讲解「{ progress: true } 水彩墨水加载动画」「{ progress: { percent } } 进度条」以及「自定义 React 节点占位」三种用法,并深入剖析其底层实现原理与语义化定制能力。读完即可在真实业务(如图片/AI 图片渐进加载)中直接落地这套占位与进度展示方案。

一、placeholder 能力总览:三种用法与类型定义

Ant Design Imageplaceholder 用于定义图片加载过程中的占位内容。根据官方 Demo(渐进加载演示说明 与对应实现 placeholder.tsx),它支持三种形态:

  1. { progress: true }:显示内置的水彩墨水(watercolor ink)加载动画,适合「不知道进度」的等待场景;
  2. { progress: { percent: number } }:显示一条带动画渐变效果的进度条,并在下方以百分比文字指示当前进度;
  3. 自定义 React 节点:完全由使用者绘制占位 UI,适合品牌化、毛玻璃等定制视觉。

在类型层面,这三种用法被统一收敛为 PlaceholderType(见 index.tsx):

export interface ImageProgressConfig {
  percent?: number;
  /** 自定义渲染函数,接收默认进度 UI 与百分比 */
  render?: (progress: React.ReactNode, percent: number) => React.ReactNode;
}

export type PlaceholderType =
  | React.ReactNode
  | {
      progress?: boolean | ImageProgressConfig;
    };

官方 API 文档(index.zh-CN.md)中对应说明为:

参数 说明 类型 默认值
placeholder 加载占位,支持 ReactNode 或配置对象 PlaceholderType -
progress 进度配置,设置为 true 显示渐变动画,设置 { percent: number } 显示进度,render 自定义渲染 boolean | ImageProgressConfig -
percent 进度值 number -
render 自定义渲染,接收默认的进度 UI 和百分比 (progress, percent) => React.ReactNode -

值得注意的是:placeholder 并未接入 ConfigProvider 的全局组件级配置(API 表格中该行「全局配置」列为 ×),因此它始终需要按组件单独传入。

二、{ progress: true }:内置水彩墨水加载动画

当不需要展示具体进度、只需一个「正在加载」的动效时,直接写:

<Image width={200} height={200} placeholder={{ progress: true }} />

2.1 布尔值背后的配置归一化

{ progress: true } 会被 usePlaceholderConfig 这一 Hook 归一化为「无 percent 的进度配置」:

export default function usePlaceholderConfig(placeholder?: PlaceholderType) {
  return useMemo(() => {
    if (!placeholder || !isPlaceholderConfig(placeholder)) {
      return {};
    }
    if (typeof placeholder.progress === 'boolean') {
      return {
        progressConfig: placeholder.progress ? {} : undefined,
      };
    }
    return {
      progressConfig: placeholder.progress,
    };
  }, [placeholder]);
}

关键点是区分「配置对象」与「React 节点」:只有普通对象且不是合法 React 元素时才被当作进度配置(isPlaceholderConfig),因此直接传入一段 JSX 会被判定为自定义节点占位而不会走进度逻辑。

2.2 五种「墨色水彩层」的实现原理

当进度配置生效后,index.tsx 会直接渲染 Progress 组件(而非底层 rc-image),其视觉核心是两枚 div 加上伪元素共 5 层径向渐变(radial-gradient)+ 高斯模糊的「墨水团」:

  • ink-1:左上蓝色云团 + ::before 中右薰衣草紫 + ::after 底部青色;
  • ink-2:粉色花瓣点缀 + ::before 淡长春花蓝点缀。

每层的尺寸为容器 150%、向左上偏移 25%,配合 filter: blur(35~45px)backdrop-filter: blur(8px) 的背景营造出湿润、晕染的水墨质感(见 style/index.ts)。动画则由 progressAnimation.ts 提供的 inkFlow1/2/3 关键帧驱动:

export const inkFlow1 = createInkFlow('antImageInkFlow1', 'translate(15%, -20%) scale(1.25)', 0.5);
export const inkFlow2 = createInkFlow(
  'antImageInkFlow2',
  'translate(-18%, 15%) scale(0.85)',
  0.9,
  'translate(0%, 0%) scale(1.1)',
  0.7,
);

关键帧在平移缩放的同时周期性调整透明度(0.5~0.9),5 层各自使用不同的 animation-duration 与负延迟(如 calc(duration + 2s)-1s)错峰运动,形成层次丰富的流动感。动画时长由主题 token progressAnimationDuration 控制,默认 3s(见 style/index.ts)。

三、{ progress: { percent } }:带百分比的进度条

当上游(如上传任务、AI 图像生成)能持续回报进度时,可以这样使用:

<Image
  width={200}
  height={200}
  placeholder={{ progress: { percent: 50 } }}
/>

3.1 percent 的边界处理与无障碍设计

查看 Progress.tsx 的实现可以发现几个工程细节:

// percent 必须是有限数字才算有效
const hasPercent = isNumber(percent) && Number.isFinite(percent);
// 宽度按 0-100 截断取整,避免进度条溢出
const percentValue = hasPercent ? Math.max(0, Math.min(100, Math.round(percent))) : 0;

// 有进度时声明为 progressbar 并同步 ARIA 属性
const ariaProps = hasPercent
  ? {
      role: 'progressbar',
      'aria-valuemin': 0,
      'aria-valuemax': 100,
      'aria-valuenow': percentValue,
      'aria-label': `${percentValue}%`,
    }
  : { 'aria-busy': true };
  • percent 会被自动收窄到 [0, 100] 并取整,即使传入负数或大于 100 也不会破坏布局;
  • 传入真实数字时,外层 DOM 具备 role="progressbar" 及完整的 aria-valuenow/min/max 语义;
  • 不传 percent(即第二节的纯动画模式)时则标记为 aria-busy,并附带一个视觉隐藏的 role="status" + aria-live="polite" 提示「Loading」,保证读屏器能感知加载中状态。

3.2 进度条的轨道与流光效果

进度条本体是一条 6px 高的 rail,其填充宽度通过 CSS 变量 --progress-percent 驱动:

<div className={`${prefixCls}-progress-rail`}
  style={{ '--progress-percent': `${percentValue}%` } as React.CSSProperties} />

对应样式(style/index.ts)用 ::before 渲染渐变轨道,width 指向该变量并带 transition 平滑过渡;同时叠加 progressActive 关键帧,使轨道内渐变背景从 200% 0 往复移动至 -200% 0,形成持续流动的微光扫过效果。轨道上方(或下方,随垂直排列布局)会以主题色文本展示 50% 这类百分比指示(indicator)。

四、render 自定义进度 UI:基于默认进度条的二次加工

如果不满意默认的「进度条 + 百分比文字」排版,ImageProgressConfig.render 允许接收「默认进度 UI」与「当前百分比」两个参数自行组合。官方 Demo 给出了两种写法:

// 完全自定义:忽略默认进度条,渲染纯文本
<Image
  width={200}
  height={200}
  placeholder={{ progress: { render: () => 'loading...' } }}
/>

// 在默认进度条下追加文字说明,实现「进度条 + 语义提示」混排
<Image
  width={200}
  height={200}
  placeholder={{
    progress: {
      percent: 75,
      render: (progress, p) => (
        <>
          {progress}
          <div style={{ marginTop: 8 }}>Generating {p}%</div>
        </>
      ),
    },
  }}
/>

Progress.tsx 可以看到,render(progressBar, percentValue) 的第一个参数是默认的进度条节点(未提供 percent 时为 null),第二个参数是收窄取整后的百分比数字——它同样是 p 的真实来源,因此自定义渲染中既能复用官方轨道,又能自由排版。

五、自定义 React 节点占位:把占位完全握在自己手里

第三种用法是直接传入一段 JSX,例如 Demo 中模拟「加载骨架 + 毛玻璃底」的占位:

<Image
  width={200}
  height={200}
  src={imageUrl}
  placeholder={
    <div
      style={{
        width: '100%',
        height: '100%',
        background: 'rgba(255, 255, 255, 0.3)',
        backdropFilter: 'blur(10px)',
        borderRadius: token.borderRadiusLG,
      }}
    />
  }
/>

自定义节点会被当作原生占位交给底层 RcImage 渲染(见 index.tsx)。值得留意的边界场景:当 src 未提供时 rc-image 会直接进入 error 状态,因此源码中有专门判断——placeholderNode && !src 时将自定义节点作为覆盖层(overlay)渲染,避免「无图即报错」;一旦提供了 src,占位则按原生加载流程在图片就绪前展示。Demo 里配合「Reload Image」按钮不断给 src 追加时间戳查询参数来触发重新加载,正是为了让占位节点在真实环境中反复可见。

六、实战:完整模拟「AI 图片渐进生成」加载流程

Demo 第二段中的 GeneratingProgress 组件是一个可以搬到业务中的完整范式:先用进度条模拟漫长的生成过程,生成完成后再切换为真实图片。其核心状态机如下(见 placeholder.tsx):

const [percent, setPercent] = useState(0);
const [status, setStatus] = useState<'idle' | 'generating' | 'complete'>('idle');

useEffect(() => {
  if (status === 'generating' && percent < 100) {
    // 每 200ms 随机累加进度,模拟服务端回报
    const timer = setTimeout(() => {
      setPercent((prev) => Math.min(prev + Math.random() * 8 + 2, 100));
    }, 200);
    return () => clearTimeout(timer);
  } else if (status === 'generating' && percent >= 100) {
    const timer = setTimeout(() => setStatus('complete'), 200);
    return () => clearTimeout(timer);
  }
}, [status, percent]);

渲染时依据状态切换两条分支:

  • complete:渲染带 srcImage,正式显示生成结果;
  • generating:渲染不带 srcImage,并传入 placeholder={{ progress: { percent, render } }}——由于此时没有 src 且是进度配置,组件会直接渲染全尺寸的进度覆盖层,视觉上严格占据 200×200 的图片占位区域(这正是前面「showProgressOverlay」分支的作用)。

这种「先占位、后出图」的写法是图片占位技术最常见的落地场景,可在生成型产品(绘图、扩图、AI 头像等)中直接复用。

七、语义化定制:styles / classNames 精确控制占位结构

若需调整占位内部细节(例如进度条高度、百分比文字间距),不必写全局 CSS 覆盖,v6 的语义化 API 已覆盖占位结构。在 index.tsxImageSemanticType 中,placeholder.progress 暴露了 root / content / rail / indicator 四段语义结构,对应 Progress.tsx 中定义的同名 ProgressClassNames / ProgressStyles

<Image
  width={200}
  height={200}
  placeholder={{ progress: { percent: 60 } }}
  styles={{
    placeholder: {
      progress: {
        root: { borderRadius: 12 },   // 整个进度容器
        rail: { height: 8 },          // 进度轨道
        indicator: { color: '#1677ff' }, // 百分比文字
      },
    },
  }}
/>

这样既能保持视觉与主题统一,又能对占位细节做像素级微调。

八、小结:如何选择三种占位方案

场景 推荐写法
只需提示「加载中」,无进度可报 placeholder={{ progress: true }}
上游有实时进度回报(上传/AI 生成/请求分块) placeholder={{ progress: { percent } }},配合 render 自定文案
需要完全定制视觉(骨架屏、毛玻璃、品牌插画) 直接传入 React 节点,如 placeholder={<Skeleton />}
进度归零起步、百分比需要本地自增驱动 参照上文「GeneratingProgress」状态机范式

以上三种用法的定义均可追溯至 PlaceholderType 类型usePlaceholderConfig 归一化 HookProgress 渲染组件占位样式 的完整链路,读者可在这些文件中继续追查水彩动画、进度轨道与无障碍属性的全部细节。

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

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388