# Avatar 头像

用于表示用户或实体的图像占位。核心在于**回退链**：只要图片拿不到，组件会自己退到可读的内容上，业务侧不必再写 `onerror` 逻辑。

## 代码演示

### 基础用法

图片、`alt` 首字符、默认插槽、人形兜底四种形态。没有 `src` 也没有 `alt` 时落到内置人形占位。

**演示说明：** 第一个头像用内联 SVG 作为图片源，避免演示依赖外部网络。

```vue
<script setup lang="ts">
import { mdiAccountOutline } from '@mdi/js'

/** 用内联 SVG 当图片源，避免演示依赖外部网络 */
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><rect width="40" height="40" fill="#4f46e5"/><circle cx="20" cy="15" r="6" fill="#fff"/><path d="M6 38c0-7 6.3-11 14-11s14 4 14 11z" fill="#fff"/></svg>`
const photo = `data:image/svg+xml,${encodeURIComponent(svg)}`
</script>

<template>
  <div class="m-row-demo">
    <MAvatar :src="photo" alt="张三" :size="44" />
    <MAvatar alt="李四" :size="44" />
    <MAvatar :size="44" color="secondary">
      <MIcon :path="mdiAccountOutline" :size="24" />
    </MAvatar>
    <MAvatar :size="44" color="info" />
  </div>
</template>
```

### 尺寸

`size` 传 `'small'` / `'default'` / `'large'` 走预设尺寸（32 / 40 / 56 px），传数字则直接按像素生效。

**演示说明：** 数字尺寸下字号按 `size * 0.42` 自动换算。

```vue
<template>
  <div class="m-row-demo">
    <MAvatar size="small" alt="Small" />
    <MAvatar size="default" alt="Default" />
    <MAvatar size="large" alt="Large" />
    <MAvatar :size="24" alt="24" color="secondary" />
    <MAvatar :size="64" alt="64" color="success" />
  </div>
</template>
```

### 形状

`circle` 正圆、`rounded` 圆角方形、`square` 直角方形。

```vue
<template>
  <div class="m-row-demo">
    <MAvatar shape="circle" :size="48" alt="Circle" />
    <MAvatar shape="rounded" :size="48" alt="Rounded" color="success" />
    <MAvatar shape="square" :size="48" alt="Square" color="warning" />
  </div>
</template>
```

### 语义色

`color` 只在文本 / 插槽 / 人形占位时起作用，图片模式下会被忽略。

```vue
<script setup lang="ts">
const colors = ['primary', 'secondary', 'success', 'warning', 'error', 'info'] as const
</script>

<template>
  <div class="m-row-demo">
    <MAvatar
      v-for="color in colors"
      :key="color"
      :color="color"
      :size="44"
      :alt="color.slice(0, 1).toUpperCase()" />
  </div>
</template>
```

### 加载失败与重新加载

第一排的头像指向一个不存在的路径，图片 `error` 后自动回退；点按钮换 `src`，组件会重置失败标记重新尝试加载。

**演示说明：** 第二个头像演示了「有 `#default` 插槽时，插槽内容优先于 `alt` 首字符」。

```vue
<script setup lang="ts">
import { ref } from 'vue'

/** 一个必然 404 的本地路径，用来触发图片加载失败的回退 */
const brokenSrc = '/miao-demo-missing-avatar.png'
const okSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><rect width="40" height="40" fill="#0ea5e9"/><circle cx="20" cy="15" r="6" fill="#fff"/><path d="M6 38c0-7 6.3-11 14-11s14 4 14 11z" fill="#fff"/></svg>`
const okSrc = `data:image/svg+xml,${encodeURIComponent(okSvg)}`

const src = ref(brokenSrc)

function toggle() {
  src.value = src.value === brokenSrc ? okSrc : brokenSrc
}
</script>

<template>
  <div class="m-row-demo">
    <MAvatar :src="src" alt="张三" :size="52" />
    <MAvatar :src="src" :size="52" color="success">
      <span>自定义</span>
    </MAvatar>
    <MButton variant="outlined" color="primary" size="small" @click="toggle">
      切换 src 重新加载
    </MButton>
  </div>
</template>
```

## API

### Props

| 属性 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `src` | `string` | `undefined` | 图片地址；加载失败自动回退到默认插槽 / 首字符 / 人形占位 |
| `alt` | `string` | `undefined` | 图片 `alt`；无图片时作为首字符占位的来源 |
| `size` | `number \| 'small' \| 'default' \| 'large'` | `40` | 数字按 px 处理，预设值对应 32 / 40 / 56 px |
| `shape` | `'circle' \| 'square' \| 'rounded'` | `'circle'` | 形状 |
| `color` | `'primary' \| 'secondary' \| 'success' \| 'warning' \| 'error' \| 'info'` | `'primary'` | 文本 / 图标占位的背景色，图片模式忽略 |

### Events

无。

### Slots

| 插槽 | 参数 | 说明 |
| --- | --- | --- |
| `default` | 无 | 自定义占位内容，优先级高于 `alt` 首字符与人形兜底 |

## 使用建议

::: tip 回退优先级
渲染顺序为「图片 → 默认插槽 → `alt` 首字符（取第一个字符并大写）→ 内置人形 SVG」。只想用一个名字做占位时，写 `<MAvatar alt="张三" />` 即可得到「张」字头像。
:::

::: tip `src` 变化会重置失败标记
组件内部用 `failed` 记录加载失败。`src` 一旦变化就会把 `failed` 置回 `false` 并重新尝试加载，因此切换用户头像时不需要换 `key` 或重建组件。
:::

::: warning 数字尺寸会同时改写字号
传数字 `size` 时，组件会把 `width` / `height` 设为该值，并把 `fontSize` 设为 `size * 0.42`。如果传入的默认插槽内容自带 `font-size`，它会覆盖这一换算。
:::

## 相关组件

- [Icon 图标](/components/icon)：默认插槽里放 `MIcon` 可以做图标头像。
- [Nav 导航](/components/nav)：导航项常配头像或图标作视觉标识。
