Skeleton骨架屏

在需要等待加载内容的位置提供一个占位图形组合。

何时使用

  • 网络较慢,需要长时间等待加载处理的情况下。

  • 图文信息内容较多的列表/卡片中。

  • 只在第一次加载数据的时候使用。

  • 可以被 Spin 完全代替,但是在可用的场景下可以比 Spin 提供更好的视觉效果和用户体验。

代码演示

Skeleton骨架屏 - 图1

基本

最简单的占位效果。

  1. import { Skeleton } from 'antd';
  2. ReactDOM.render(<Skeleton />, mountNode);

Skeleton骨架屏 - 图2

复杂的组合

更复杂的组合。

  1. import { Skeleton } from 'antd';
  2. ReactDOM.render(<Skeleton avatar paragraph={{ rows: 4 }} />, mountNode);

Skeleton骨架屏 - 图3

动画效果

显示动画效果。

  1. import { Skeleton } from 'antd';
  2. ReactDOM.render(<Skeleton active />, mountNode);

Skeleton骨架屏 - 图4

骨架按钮、头像和输入框。

骨架按钮、头像和输入框。

  1. import { Skeleton, Switch, Form, Radio } from 'antd';
  2. class Demo extends React.Component {
  3. state = {
  4. buttonActive: false,
  5. avatarActive: false,
  6. inputActive: false,
  7. buttonSize: 'default',
  8. avatarSize: 'default',
  9. inputSize: 'default',
  10. buttonShape: 'default',
  11. avatarShape: 'circle',
  12. };
  13. handleActiveChange = prop => checked => {
  14. this.setState({ [prop]: checked });
  15. };
  16. handleSizeChange = prop => e => {
  17. this.setState({ [prop]: e.target.value });
  18. };
  19. handleShapeChange = prop => e => {
  20. this.setState({ [prop]: e.target.value });
  21. };
  22. render() {
  23. const {
  24. buttonActive,
  25. avatarActive,
  26. inputActive,
  27. buttonSize,
  28. avatarSize,
  29. inputSize,
  30. buttonShape,
  31. avatarShape,
  32. } = this.state;
  33. return (
  34. <div>
  35. <div>
  36. <Form layout="inline" style={{ marginBottom: 16 }}>
  37. <Form.Item label="ButtonActive">
  38. <Switch checked={buttonActive} onChange={this.handleActiveChange('buttonActive')} />
  39. </Form.Item>
  40. <Form.Item label="ButtonSize">
  41. <Radio.Group value={buttonSize} onChange={this.handleSizeChange('buttonSize')}>
  42. <Radio.Button value="default">Default</Radio.Button>
  43. <Radio.Button value="large">Large</Radio.Button>
  44. <Radio.Button value="small">Small</Radio.Button>
  45. </Radio.Group>
  46. </Form.Item>
  47. <Form.Item label="ButtonShape">
  48. <Radio.Group value={buttonShape} onChange={this.handleShapeChange('buttonShape')}>
  49. <Radio.Button value="default">Default</Radio.Button>
  50. <Radio.Button value="round">Round</Radio.Button>
  51. <Radio.Button value="circle">Circle</Radio.Button>
  52. </Radio.Group>
  53. </Form.Item>
  54. </Form>
  55. <Skeleton.Button active={buttonActive} size={buttonSize} shape={buttonShape} />
  56. </div>
  57. <br />
  58. <div>
  59. <Form layout="inline" style={{ marginBottom: 16 }}>
  60. <Form.Item label="AvatarActive">
  61. <Switch checked={avatarActive} onChange={this.handleActiveChange('avatarActive')} />
  62. </Form.Item>
  63. <Form.Item label="AvatarSize">
  64. <Radio.Group value={avatarSize} onChange={this.handleSizeChange('avatarSize')}>
  65. <Radio.Button value="default">Default</Radio.Button>
  66. <Radio.Button value="large">Large</Radio.Button>
  67. <Radio.Button value="small">Small</Radio.Button>
  68. </Radio.Group>
  69. </Form.Item>
  70. <Form.Item label="AvatarShape">
  71. <Radio.Group value={avatarShape} onChange={this.handleShapeChange('avatarShape')}>
  72. <Radio.Button value="square">Square</Radio.Button>
  73. <Radio.Button value="circle">Circle</Radio.Button>
  74. </Radio.Group>
  75. </Form.Item>
  76. </Form>
  77. <Skeleton.Avatar active={avatarActive} size={avatarSize} shape={avatarShape} />
  78. </div>
  79. <br />
  80. <div>
  81. <Form layout="inline" style={{ marginBottom: 16 }}>
  82. <Form.Item label="InputActive">
  83. <Switch checked={inputActive} onChange={this.handleActiveChange('inputActive')} />
  84. </Form.Item>
  85. <Form.Item label="InputSize">
  86. <Radio.Group value={inputSize} onChange={this.handleSizeChange('inputSize')}>
  87. <Radio.Button value="default">Default</Radio.Button>
  88. <Radio.Button value="large">Large</Radio.Button>
  89. <Radio.Button value="small">Small</Radio.Button>
  90. </Radio.Group>
  91. </Form.Item>
  92. </Form>
  93. <Skeleton.Input style={{ width: '300px' }} active={inputActive} size={inputSize} />
  94. </div>
  95. </div>
  96. );
  97. }
  98. }
  99. ReactDOM.render(<Demo />, mountNode);

Skeleton骨架屏 - 图5

包含子组件

加载占位图包含子组件。

  1. import { Skeleton, Button } from 'antd';
  2. class Demo extends React.Component {
  3. state = {
  4. loading: false,
  5. };
  6. showSkeleton = () => {
  7. this.setState({ loading: true });
  8. setTimeout(() => {
  9. this.setState({ loading: false });
  10. }, 3000);
  11. };
  12. render() {
  13. return (
  14. <div className="article">
  15. <Skeleton loading={this.state.loading}>
  16. <div>
  17. <h4>Ant Design, a design language</h4>
  18. <p>
  19. We supply a series of design principles, practical patterns and high quality design
  20. resources (Sketch and Axure), to help people create their product prototypes
  21. beautifully and efficiently.
  22. </p>
  23. </div>
  24. </Skeleton>
  25. <Button onClick={this.showSkeleton} disabled={this.state.loading}>
  26. Show Skeleton
  27. </Button>
  28. </div>
  29. );
  30. }
  31. }
  32. ReactDOM.render(<Demo />, mountNode);

Skeleton骨架屏 - 图6

列表

在列表组件中使用加载占位符。

  1. import { Skeleton, Switch, List, Avatar } from 'antd';
  2. import { StarOutlined, LikeOutlined, MessageOutlined } from '@ant-design/icons';
  3. const listData = [];
  4. for (let i = 0; i < 3; i++) {
  5. listData.push({
  6. href: 'http://ant.design',
  7. title: `ant design part ${i}`,
  8. avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
  9. description:
  10. 'Ant Design, a design language for background applications, is refined by Ant UED Team.',
  11. content:
  12. 'We supply a series of design principles, practical patterns and high quality design resources (Sketch and Axure), to help people create their product prototypes beautifully and efficiently.',
  13. });
  14. }
  15. const IconText = ({ icon, text }) => (
  16. <span>
  17. {React.createElement(icon, { style: { marginRight: 8 } })}
  18. {text}
  19. </span>
  20. );
  21. class App extends React.Component {
  22. state = {
  23. loading: true,
  24. };
  25. onChange = checked => {
  26. this.setState({ loading: !checked });
  27. };
  28. render() {
  29. const { loading } = this.state;
  30. return (
  31. <div>
  32. <Switch checked={!loading} onChange={this.onChange} />
  33. <List
  34. itemLayout="vertical"
  35. size="large"
  36. dataSource={listData}
  37. renderItem={item => (
  38. <List.Item
  39. key={item.title}
  40. actions={
  41. !loading && [
  42. <IconText icon={StarOutlined} text="156" key="list-vertical-star-o" />,
  43. <IconText icon={LikeOutlined} text="156" key="list-vertical-like-o" />,
  44. <IconText icon={MessageOutlined} text="2" key="list-vertical-message" />,
  45. ]
  46. }
  47. extra={
  48. !loading && (
  49. <img
  50. width={272}
  51. alt="logo"
  52. src="https://gw.alipayobjects.com/zos/rmsportal/mqaQswcyDLcXyDKnZfES.png"
  53. />
  54. )
  55. }
  56. >
  57. <Skeleton loading={loading} active avatar>
  58. <List.Item.Meta
  59. avatar={<Avatar src={item.avatar} />}
  60. title={<a href={item.href}>{item.title}</a>}
  61. description={item.description}
  62. />
  63. {item.content}
  64. </Skeleton>
  65. </List.Item>
  66. )}
  67. />
  68. </div>
  69. );
  70. }
  71. }
  72. ReactDOM.render(<App />, mountNode);

API

Skeleton

属性说明类型默认值
active是否展示动画效果booleanfalse
avatar是否显示头像占位图boolean | SkeletonAvatarPropsfalse
loadingtrue 时,显示占位图。反之则直接展示子组件boolean-
paragraph是否显示段落占位图boolean | SkeletonParagraphPropstrue
title是否显示标题占位图boolean | SkeletonTitlePropstrue

SkeletonAvatarProps

属性说明类型默认值
active是否展示动画效果,仅在单独使用头像骨架时生效booleanfalse
size设置头像占位图的大小number | large | small | default-
shape指定头像的形状circle | square-

SkeletonTitleProps

属性说明类型默认值
width设置标题占位图的宽度number | string-

SkeletonParagraphProps

属性说明类型默认值
rows设置段落占位图的行数number-
width设置段落占位图的宽度,若为数组时则为对应的每行宽度,反之则是最后一行的宽度number | string | Array<number | string>-

SkeletonButtonProps

属性说明类型默认值
active是否展示动画效果booleanfalse
size设置按钮的大小large | small | default-
shape指定按钮的形状circle | round | default-

SkeletonInputProps

属性说明类型默认值
active是否展示动画效果booleanfalse
size设置按钮的大小large | small | default-