---
nav:
  title: 组件
  order: 1
group:
  title: Data Display
  order: 1
title: GraphicTextCard
order: 1
category: atom
---

# GraphicTextCard 图文卡片

GraphicTextCard 是一个图文卡片组件，结合图标/图片、文本和状态标识，专为标签页、分类导航等场景设计，支持多种布局方式和状态管理。

## 何时使用

- 需要展示带图片或图标的标签项
- 作为垂直或横向的导航卡片
- 需要带角标提示的分类入口
- 商品分类、功能入口等图文结合场景
- 需要支持激活/禁用/加载等多种状态的卡片

## 基础使用

### 基础图文卡片

最简单的用法，传入文本和图片。

```tsx
import { PisellCards } from '@pisell/materials';

export default () => {
  return (
    <div style={{ display: 'flex', gap: '16px' }}>
      <PisellCards.GraphicTextCard
        text="分类一"
        image="https://via.placeholder.com/80"
      />
      <PisellCards.GraphicTextCard
        text="分类二"
        image="https://via.placeholder.com/80"
      />
      <PisellCards.GraphicTextCard
        text="分类三"
        image="https://via.placeholder.com/80"
      />
    </div>
  );
};
```

## 样式变体

GraphicTextCard 支持 4 种样式变体，通过 `variant` 属性控制。

### 垂直布局-图片（vertical-image）

上图下文的垂直布局，适合图片展示。

```tsx
import { PisellCards } from '@pisell/materials';

export default () => {
  return (
    <div style={{ display: 'flex', gap: '16px' }}>
      <PisellCards.GraphicTextCard
        text="分类一"
        image="https://via.placeholder.com/80"
        variant="vertical-image"
      />
      <PisellCards.GraphicTextCard
        text="分类二"
        image="https://via.placeholder.com/80"
        variant="vertical-image"
        active={{ value: true }}
      />
      <PisellCards.GraphicTextCard
        text="分类三"
        image="https://via.placeholder.com/80"
        variant="vertical-image"
        disabled={{ value: true }}
      />
    </div>
  );
};
```

### 垂直布局-图标（vertical-icon）

上图标下文的垂直布局，适合图标展示。

```tsx
import { PisellCards } from '@pisell/materials';
import {
  HomeOutlined,
  ShoppingOutlined,
  UserOutlined,
} from '@ant-design/icons';

export default () => {
  return (
    <div style={{ display: 'flex', gap: '16px' }}>
      <PisellCards.GraphicTextCard
        text="首页"
        icon={<HomeOutlined />}
        variant="vertical-icon"
      />
      <PisellCards.GraphicTextCard
        text="商城"
        icon={<ShoppingOutlined />}
        variant="vertical-icon"
        active={{ value: true }}
      />
      <PisellCards.GraphicTextCard
        text="我的"
        icon={<UserOutlined />}
        variant="vertical-icon"
      />
    </div>
  );
};
```

### 横向布局（horizontal）

左图右文的横向布局。

```tsx
import { PisellCards } from '@pisell/materials';
import { AppstoreOutlined } from '@ant-design/icons';

export default () => {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
      <PisellCards.GraphicTextCard
        text="商品分类"
        icon={<AppstoreOutlined />}
        variant="horizontal"
      />
      <PisellCards.GraphicTextCard
        text="热门推荐"
        icon={<AppstoreOutlined />}
        variant="horizontal"
        active={{ value: true }}
      />
    </div>
  );
};
```

### 卡片式（card）

带边框和背景的卡片样式。

```tsx
import { PisellCards } from '@pisell/materials';

export default () => {
  return (
    <div style={{ display: 'flex', gap: '16px' }}>
      <PisellCards.GraphicTextCard
        text="会员中心"
        image="https://via.placeholder.com/120"
        variant="card"
      />
      <PisellCards.GraphicTextCard
        text="VIP 专区"
        image="https://via.placeholder.com/120"
        variant="card"
        active={{ value: true }}
      />
    </div>
  );
};
```

## 尺寸

GraphicTextCard 支持 3 种尺寸。

```tsx
import { PisellCards } from '@pisell/materials';
import { HomeOutlined } from '@ant-design/icons';

export default () => {
  return (
    <div style={{ display: 'flex', gap: '16px', alignItems: 'flex-end' }}>
      <PisellCards.GraphicTextCard
        text="小尺寸"
        icon={<HomeOutlined />}
        variant="vertical-icon"
        size="small"
      />
      <PisellCards.GraphicTextCard
        text="默认尺寸"
        icon={<HomeOutlined />}
        variant="vertical-icon"
        size="default"
      />
      <PisellCards.GraphicTextCard
        text="大尺寸"
        icon={<HomeOutlined />}
        variant="vertical-icon"
        size="large"
      />
    </div>
  );
};
```

## 状态管理

### 激活状态

```tsx
import { PisellCards } from '@pisell/materials';
import {
  HomeOutlined,
  ShoppingOutlined,
  UserOutlined,
} from '@ant-design/icons';
import { useState } from 'react';

export default () => {
  const [activeKey, setActiveKey] = useState('home');

  return (
    <div style={{ display: 'flex', gap: '16px' }}>
      <PisellCards.GraphicTextCard
        text="首页"
        icon={<HomeOutlined />}
        variant="vertical-icon"
        active={{ value: activeKey === 'home' }}
        onClick={() => setActiveKey('home')}
      />
      <PisellCards.GraphicTextCard
        text="商城"
        icon={<ShoppingOutlined />}
        variant="vertical-icon"
        active={{ value: activeKey === 'shop' }}
        onClick={() => setActiveKey('shop')}
      />
      <PisellCards.GraphicTextCard
        text="我的"
        icon={<UserOutlined />}
        variant="vertical-icon"
        active={{ value: activeKey === 'user' }}
        onClick={() => setActiveKey('user')}
      />
    </div>
  );
};
```

### 禁用状态

```tsx
import { PisellCards } from '@pisell/materials';
import { HomeOutlined } from '@ant-design/icons';

export default () => {
  return (
    <div style={{ display: 'flex', gap: '16px' }}>
      <PisellCards.GraphicTextCard
        text="正常状态"
        icon={<HomeOutlined />}
        variant="vertical-icon"
        onClick={() => alert('点击成功')}
      />
      <PisellCards.GraphicTextCard
        text="禁用状态"
        icon={<HomeOutlined />}
        variant="vertical-icon"
        disabled={{ value: true }}
        onClick={() => alert('不会触发')}
      />
    </div>
  );
};
```

### 加载状态

```tsx
import { PisellCards } from '@pisell/materials';
import { HomeOutlined } from '@ant-design/icons';
import { Spin } from 'antd';

export default () => {
  return (
    <div style={{ display: 'flex', gap: '16px' }}>
      <PisellCards.GraphicTextCard
        text="加载中"
        icon={<HomeOutlined />}
        variant="vertical-icon"
        loading={{
          value: true,
          extra: <Spin size="small" />,
        }}
      />
    </div>
  );
};
```

## 角标配置

### 红点角标

```tsx
import { PisellCards } from '@pisell/materials';
import { MessageOutlined } from '@ant-design/icons';

export default () => {
  return (
    <PisellCards.GraphicTextCard
      text="消息"
      icon={<MessageOutlined />}
      variant="vertical-icon"
      badge={{ type: 'dot' }}
    />
  );
};
```

### 数字角标

```tsx
import { PisellCards } from '@pisell/materials';
import { MessageOutlined } from '@ant-design/icons';

export default () => {
  return (
    <PisellCards.GraphicTextCard
      text="消息"
      icon={<MessageOutlined />}
      variant="vertical-icon"
      badge={{ type: 'number', content: 99 }}
    />
  );
};
```

### 文本角标

```tsx
import { PisellCards } from '@pisell/materials';
import { GiftOutlined } from '@ant-design/icons';

export default () => {
  return (
    <PisellCards.GraphicTextCard
      text="活动"
      icon={<GiftOutlined />}
      variant="vertical-icon"
      badge={{ type: 'text', content: 'New' }}
    />
  );
};
```

### 角标位置

```tsx
import { PisellCards } from '@pisell/materials';
import { HomeOutlined } from '@ant-design/icons';

export default () => {
  return (
    <div style={{ display: 'flex', gap: '16px' }}>
      <PisellCards.GraphicTextCard
        text="右上角"
        icon={<HomeOutlined />}
        variant="vertical-icon"
        badge={{ type: 'number', content: 5, position: 'top-right' }}
      />
      <PisellCards.GraphicTextCard
        text="左上角"
        icon={<HomeOutlined />}
        variant="vertical-icon"
        badge={{ type: 'number', content: 5, position: 'top-left' }}
      />
      <PisellCards.GraphicTextCard
        text="右下角"
        icon={<HomeOutlined />}
        variant="vertical-icon"
        badge={{ type: 'number', content: 5, position: 'bottom-right' }}
      />
      <PisellCards.GraphicTextCard
        text="左下角"
        icon={<HomeOutlined />}
        variant="vertical-icon"
        badge={{ type: 'number', content: 5, position: 'bottom-left' }}
      />
    </div>
  );
};
```

## 图形区域配置

### 自定义图形尺寸

```tsx
import { PisellCards } from '@pisell/materials';

export default () => {
  return (
    <div style={{ display: 'flex', gap: '16px' }}>
      <PisellCards.GraphicTextCard
        text="自定义尺寸"
        image="https://via.placeholder.com/100"
        variant="vertical-image"
        graphicConfig={{
          width: 100,
          height: 100,
        }}
      />
    </div>
  );
};
```

### 图标样式配置

```tsx
import { PisellCards } from '@pisell/materials';
import { StarOutlined } from '@ant-design/icons';

export default () => {
  return (
    <div style={{ display: 'flex', gap: '16px' }}>
      <PisellCards.GraphicTextCard
        text="自定义图标"
        icon={<StarOutlined />}
        variant="vertical-icon"
        graphicConfig={{
          iconSize: 32,
          iconColor: '#ff4d4f',
          background: '#fff1f0',
          borderRadius: 8,
        }}
      />
    </div>
  );
};
```

### 图形区域插槽

完全自定义图形区域。

```tsx
import { PisellCards } from '@pisell/materials';

export default () => {
  return (
    <PisellCards.GraphicTextCard
      text="自定义图形"
      variant="vertical-icon"
      graphicSlot={
        <div
          style={{
            width: 64,
            height: 64,
            background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
            borderRadius: 8,
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            color: '#fff',
            fontSize: 24,
          }}
        >
          🎉
        </div>
      }
    />
  );
};
```

## 文本配置

### 字体样式

```tsx
import { PisellCards } from '@pisell/materials';
import { HomeOutlined } from '@ant-design/icons';

export default () => {
  return (
    <PisellCards.GraphicTextCard
      text="自定义文本"
      icon={<HomeOutlined />}
      variant="vertical-icon"
      textConfig={{
        fontSize: 18,
        fontWeight: 'bold',
        color: '#1890ff',
      }}
    />
  );
};
```

### 文本省略

```tsx
import { PisellCards } from '@pisell/materials';
import { HomeOutlined } from '@ant-design/icons';

export default () => {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
      <PisellCards.GraphicTextCard
        text="这是一段很长很长很长很长很长的文本内容"
        icon={<HomeOutlined />}
        variant="horizontal"
        textConfig={{ maxLines: 1, ellipsis: true }}
        style={{ width: 200 }}
      />
      <PisellCards.GraphicTextCard
        text="这是一段很长很长很长很长很长的文本内容，会显示两行然后省略"
        icon={<HomeOutlined />}
        variant="horizontal"
        textConfig={{ maxLines: 2, ellipsis: true }}
        style={{ width: 200 }}
      />
    </div>
  );
};
```

### 文本对齐

```tsx
import { PisellCards } from '@pisell/materials';
import { HomeOutlined } from '@ant-design/icons';

export default () => {
  return (
    <div style={{ display: 'flex', gap: '16px' }}>
      <PisellCards.GraphicTextCard
        text="左对齐"
        icon={<HomeOutlined />}
        variant="vertical-icon"
        textConfig={{ textAlign: 'left' }}
      />
      <PisellCards.GraphicTextCard
        text="居中对齐"
        icon={<HomeOutlined />}
        variant="vertical-icon"
        textConfig={{ textAlign: 'center' }}
      />
      <PisellCards.GraphicTextCard
        text="右对齐"
        icon={<HomeOutlined />}
        variant="vertical-icon"
        textConfig={{ textAlign: 'right' }}
      />
    </div>
  );
};
```

## 宽度模式

### 自动宽度（auto）

内容撑满，最大宽度受 maxWidth 限制。

```tsx
import { PisellCards } from '@pisell/materials';
import { HomeOutlined } from '@ant-design/icons';

export default () => {
  return (
    <PisellCards.GraphicTextCard
      text="自动宽度"
      icon={<HomeOutlined />}
      variant="horizontal"
      widthMode="auto"
      maxWidth={300}
    />
  );
};
```

### 固定宽度（fixed）

固定指定宽度。

```tsx
import { PisellCards } from '@pisell/materials';
import { HomeOutlined } from '@ant-design/icons';

export default () => {
  return (
    <PisellCards.GraphicTextCard
      text="固定宽度"
      icon={<HomeOutlined />}
      variant="horizontal"
      widthMode="fixed"
      width={200}
    />
  );
};
```

### 撑满容器（full）

撑满父容器宽度。

```tsx
import { PisellCards } from '@pisell/materials';
import { HomeOutlined } from '@ant-design/icons';

export default () => {
  return (
    <div style={{ width: '100%', border: '1px dashed #ccc', padding: 16 }}>
      <PisellCards.GraphicTextCard
        text="撑满容器"
        icon={<HomeOutlined />}
        variant="horizontal"
        widthMode="full"
      />
    </div>
  );
};
```

## 插槽

### 前置插槽

在图形区域前添加自定义内容。

```tsx
import { PisellCards } from '@pisell/materials';
import { HomeOutlined } from '@ant-design/icons';

export default () => {
  return (
    <PisellCards.GraphicTextCard
      text="前置插槽"
      icon={<HomeOutlined />}
      variant="horizontal"
      prefixSlot={
        <div
          style={{
            width: 4,
            height: 40,
            background: '#1890ff',
            borderRadius: 2,
          }}
        />
      }
    />
  );
};
```

### 后置插槽

在文本内容后添加自定义内容。

```tsx
import { PisellCards } from '@pisell/materials';
import { HomeOutlined, RightOutlined } from '@ant-design/icons';

export default () => {
  return (
    <PisellCards.GraphicTextCard
      text="后置插槽"
      icon={<HomeOutlined />}
      variant="horizontal"
      suffixSlot={<RightOutlined style={{ color: '#999' }} />}
    />
  );
};
```

## 自定义渲染

使用 render 函数完全自定义渲染内容。

```tsx
import { PisellCards } from '@pisell/materials';

export default () => {
  return (
    <PisellCards.GraphicTextCard
      text="自定义渲染"
      render={(props) => (
        <div
          style={{
            padding: '16px',
            background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
            color: '#fff',
            borderRadius: 8,
          }}
        >
          <div style={{ fontSize: 18, fontWeight: 'bold' }}>{props.text}</div>
          <div style={{ fontSize: 12, marginTop: 8, opacity: 0.8 }}>
            完全自定义的内容
          </div>
        </div>
      )}
    />
  );
};
```

## 综合示例

### 导航菜单

```tsx
import { PisellCards } from '@pisell/materials';
import {
  HomeOutlined,
  ShoppingOutlined,
  UserOutlined,
  MessageOutlined,
} from '@ant-design/icons';
import { useState } from 'react';

export default () => {
  const [activeKey, setActiveKey] = useState('home');

  const menuItems = [
    { key: 'home', icon: <HomeOutlined />, text: '首页' },
    { key: 'shop', icon: <ShoppingOutlined />, text: '商城' },
    { key: 'message', icon: <MessageOutlined />, text: '消息', badge: 5 },
    { key: 'user', icon: <UserOutlined />, text: '我的' },
  ];

  return (
    <div style={{ display: 'flex', gap: '16px' }}>
      {menuItems.map((item) => (
        <PisellCards.GraphicTextCard
          key={item.key}
          text={item.text}
          icon={item.icon}
          variant="vertical-icon"
          active={{ value: activeKey === item.key }}
          badge={
            item.badge ? { type: 'number', content: item.badge } : undefined
          }
          onClick={() => setActiveKey(item.key)}
        />
      ))}
    </div>
  );
};
```

### 商品分类

```tsx
import { PisellCards } from '@pisell/materials';

export default () => {
  const categories = [
    { id: 1, name: '电子产品', image: 'https://via.placeholder.com/80' },
    {
      id: 2,
      name: '服装鞋包',
      image: 'https://via.placeholder.com/80',
      hot: true,
    },
    { id: 3, name: '美妆护肤', image: 'https://via.placeholder.com/80' },
    {
      id: 4,
      name: '食品生鲜',
      image: 'https://via.placeholder.com/80',
      badge: 'New',
    },
  ];

  return (
    <div style={{ display: 'flex', gap: '16px', flexWrap: 'wrap' }}>
      {categories.map((category) => (
        <PisellCards.GraphicTextCard
          key={category.id}
          text={category.name}
          image={category.image}
          variant="vertical-image"
          badge={
            category.hot
              ? { type: 'text', content: 'Hot', color: '#ff4d4f' }
              : category.badge
              ? { type: 'text', content: category.badge, color: '#52c41a' }
              : undefined
          }
          onClick={() => console.log('点击分类:', category.name)}
        />
      ))}
    </div>
  );
};
```

## API

### GraphicTextCardProps

| 参数          | 说明                                                          | 类型                                                            | 默认值             |
| ------------- | ------------------------------------------------------------- | --------------------------------------------------------------- | ------------------ |
| text          | 卡片显示的文本内容（必填）                                    | `ReactNode`                                                     | -                  |
| variant       | 卡片样式变体                                                  | `'vertical-image' \| 'vertical-icon' \| 'horizontal' \| 'card'` | `'vertical-image'` |
| size          | 卡片尺寸                                                      | `'small' \| 'default' \| 'large'`                               | `'default'`        |
| clickable     | 是否可点击                                                    | `boolean`                                                       | `true`             |
| image         | 图片地址（与 icon 二选一，优先使用 image）                    | `string`                                                        | -                  |
| icon          | 图标（与 image 二选一）                                       | `ReactNode`                                                     | -                  |
| graphicConfig | 图形区域配置                                                  | `GraphicConfig`                                                 | -                  |
| graphicSlot   | 图形区域插槽（优先级高于 image 和 icon）                      | `ReactNode`                                                     | -                  |
| badge         | 角标配置                                                      | `BadgeConfig`                                                   | -                  |
| prefixSlot    | 前置插槽                                                      | `ReactNode`                                                     | -                  |
| suffixSlot    | 后置插槽                                                      | `ReactNode`                                                     | -                  |
| textConfig    | 文本配置                                                      | `TextConfig`                                                    | -                  |
| widthMode     | 宽度模式                                                      | `'auto' \| 'fixed' \| 'full'`                                   | `'auto'`           |
| width         | 固定宽度值（widthMode='fixed' 时有效）                        | `number \| string`                                              | -                  |
| maxWidth      | 最大宽度（widthMode='auto' 时有效）                           | `number \| string`                                              | `400`              |
| active        | 激活状态配置                                                  | `StateConfig`                                                   | -                  |
| disabled      | 禁用状态配置                                                  | `StateConfig`                                                   | -                  |
| loading       | 加载状态配置                                                  | `StateConfig`                                                   | -                  |
| onClick       | 点击事件（clickable=true 且不在 disabled/loading 状态时触发） | `(event: MouseEvent) => void`                                   | -                  |
| render        | 自定义渲染函数                                                | `(props: GraphicTextCardProps) => ReactNode`                    | -                  |
| className     | 自定义样式类名                                                | `string`                                                        | -                  |
| style         | 自定义样式                                                    | `CSSProperties`                                                 | -                  |

### GraphicConfig

| 参数         | 说明                                     | 类型               | 默认值 |
| ------------ | ---------------------------------------- | ------------------ | ------ |
| width        | 图形区域宽度（单位：px）                 | `number`           | -      |
| height       | 图形区域高度（单位：px）                 | `number`           | -      |
| borderRadius | 图形区域圆角                             | `number \| string` | -      |
| background   | 图形区域背景色                           | `string`           | -      |
| border       | 图形区域边框                             | `string`           | -      |
| boxShadow    | 图形区域阴影                             | `string`           | -      |
| padding      | 图形区域内边距                           | `number \| string` | -      |
| iconSize     | 图标大小（当使用 icon 时有效，单位：px） | `number`           | -      |
| iconColor    | 图标颜色（当使用 icon 时有效）           | `string`           | -      |
| style        | 自定义样式                               | `CSSProperties`    | -      |

### BadgeConfig

| 参数     | 说明                                          | 类型                                                           | 默认值        |
| -------- | --------------------------------------------- | -------------------------------------------------------------- | ------------- |
| type     | 角标类型                                      | `'dot' \| 'number' \| 'text'`                                  | `'dot'`       |
| content  | 角标内容（数字或文本）                        | `ReactNode`                                                    | -             |
| position | 角标位置                                      | `'top-right' \| 'top-left' \| 'bottom-right' \| 'bottom-left'` | `'top-right'` |
| offset   | 角标偏移量 [x, y]（正数向右/下，负数向左/上） | `[number, number]`                                             | -             |
| color    | 角标颜色                                      | `string`                                                       | -             |
| style    | 角标自定义样式                                | `CSSProperties`                                                | -             |

### TextConfig

| 参数       | 说明                 | 类型                            | 默认值   |
| ---------- | -------------------- | ------------------------------- | -------- |
| fontSize   | 字体大小（单位：px） | `number`                        | -        |
| fontWeight | 字体粗细             | `string \| number`              | -        |
| color      | 文本颜色             | `string`                        | -        |
| maxLines   | 最大显示行数         | `number`                        | `1`      |
| ellipsis   | 是否显示省略号       | `boolean`                       | `true`   |
| textAlign  | 文本对齐方式         | `'left' \| 'center' \| 'right'` | `'left'` |

### 状态配置（StateConfig）

继承自 `PisellBasicCardProps`，用于 `active`、`disabled`、`loading` 等状态配置。

| 参数      | 说明                   | 类型                       | 默认值 |
| --------- | ---------------------- | -------------------------- | ------ |
| value     | 是否处于该状态         | `boolean`                  | -      |
| style     | 该状态下的自定义样式   | `CSSProperties`            | -      |
| className | 该状态下的自定义类名   | `string`                   | -      |
| onChange  | 状态改变回调           | `(value: boolean) => void` | -      |
| extra     | 该状态下额外的渲染内容 | `ReactNode`                | -      |

## 注意事项

1. **图形优先级**：graphicSlot > image > icon
2. **状态优先级**：loading > disabled > active
3. **宽度模式**：
   - auto 模式下，内容撑满但不超过 maxWidth
   - fixed 模式下，使用固定 width 值
   - full 模式下，撑满父容器
4. **点击事件**：disabled 和 loading 状态下，点击事件不会触发
5. **图形尺寸**：如果不设置 graphicConfig 的 width/height，将根据 variant 和 size 自动计算
6. **主题色变量**：组件使用 CSS 变量 `--theme-color` 作为主题色，可通过修改 CSS 变量自定义主题色
7. **无障碍访问**：组件已添加 ARIA 属性支持（role、aria-disabled、tabIndex）
