# Button 按钮

最常用的操作触发器。提供六种语义色、五种外观变体与多种形状，内置 Material 涟漪反馈，点击默认带 200ms 节流以避免重复提交。

## 代码演示

### 基础用法

通过 `variant` 切换外观，`color` 指定语义色。默认变体是 `text`，业务里最常用的是 `contained` 与 `outlined`。

**演示说明：** 点击按钮会通过编程式 `toast.success()` 弹出提示。

```vue
<script setup lang="ts">
import { toast } from 'miao-design'

function handleClick() {
  toast.success('按钮被点击')
}
</script>

<template>
  <div class="m-row-demo">
    <MButton variant="contained" color="primary" @click="handleClick">主要按钮</MButton>
    <MButton variant="outlined" color="primary">次要按钮</MButton>
    <MButton variant="text" color="primary">文字按钮</MButton>
    <MButton variant="contained" color="primary" disabled>禁用状态</MButton>
  </div>
</template>
```

### 外观变体

`contained` 实底、`outlined` 描边、`tonal` 浅底、`text` 纯文字。

```vue
<template>
  <div class="m-row-demo">
    <MButton variant="contained" color="primary">contained</MButton>
    <MButton variant="outlined" color="primary">outlined</MButton>
    <MButton variant="tonal" color="primary">tonal</MButton>
    <MButton variant="text" color="primary">text</MButton>
  </div>
</template>
```

### 语义色

六种语义色与组件的 `--m-*` 主题令牌一一对应，切换主题时无需改动业务代码。

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

<template>
  <div class="m-row-demo">
    <MButton v-for="color in colors" :key="color" variant="contained" :color="color">
      {{ color }}
    </MButton>
  </div>
</template>
```

### 尺寸

`small` / `default` / `large` 三档，高度取自全局令牌 `--m-size-small`（28px）、`--m-size-default`（36px）、`--m-size-large`（48px）。

```vue
<template>
  <div class="m-row-demo">
    <MButton variant="contained" color="primary" size="small">small</MButton>
    <MButton variant="contained" color="primary" size="default">default</MButton>
    <MButton variant="contained" color="primary" size="large">large</MButton>
  </div>
</template>
```

### 加载态

`loading` 会显示旋转指示器并禁用按钮，适合提交类操作。

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

const loading = ref(false)

function startLoading() {
  loading.value = true
  window.setTimeout(() => (loading.value = false), 2000)
}
</script>

<template>
  <div class="m-row-demo">
    <MButton variant="contained" color="primary" :loading="loading" @click="startLoading">
      {{ loading ? '提交中' : '点击提交' }}
    </MButton>
    <MButton variant="outlined" color="error" :loading="true">加载中</MButton>
    <MButton variant="text" color="primary" :loading="true">text 加载</MButton>
  </div>
</template>
```

### 形状

`shape="round"` 得到胶囊形，`shape="circle"` 得到正方形圆形按钮（配合 `MIcon` 做纯图标按钮）。

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

<template>
  <div class="m-row-demo">
    <MButton variant="contained" color="primary" shape="round">
      <MIcon :path="mdiAccountPlusOutline" :size="18" />
      圆角按钮
    </MButton>
    <MButton variant="contained" color="secondary" shape="circle" aria-label="发送">
      <MIcon :path="mdiSendOutline" :size="18" />
    </MButton>
    <MButton variant="outlined" color="primary" shape="round">round</MButton>
  </div>
</template>
```

## API

### Props

| 属性 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `color` | `'primary' \| 'secondary' \| 'error' \| 'success' \| 'warning' \| 'info'` | `undefined` | 语义色；在 `MButtonGroup` 内若未设置则继承组的 `color` |
| `variant` | `'text' \| 'outlined' \| 'contained' \| 'tonal' \| 'circle'` | `'text'` | 外观变体 |
| `size` | `'small' \| 'default' \| 'large'` | `'default'` | 尺寸 |
| `shape` | `'round' \| 'circle' \| ''` | `''` | 形状：胶囊 / 圆形 / 默认 |
| `disabled` | `boolean` | `false` | 是否禁用 |
| `loading` | `boolean` | `false` | 加载态：显示旋转指示器并禁用交互 |
| `block` | `boolean` | `false` | 占满父容器宽度（`shape="circle"` 时忽略） |
| `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | 原生 `button` 的 `type` |
| `throttle` | `number` | `200` | 点击事件节流时间（ms） |

### Events

| 事件 | 参数 | 说明 |
| --- | --- | --- |
| `click` | `event: MouseEvent` | 点击事件；经过 `throttle` 节流，`disabled` / `loading` 时不触发 |

### Slots

| 插槽 | 参数 | 说明 |
| --- | --- | --- |
| `default` | 无 | 按钮内容，可混排文本与 `MIcon` |

## 使用建议

::: tip 按钮内容可以带图标
`MButton` 内部是 flex 布局，直接往默认插槽里放 `MIcon` 即可自动对齐，不需要额外包一层容器。

```vue
<MButton variant="contained" color="primary">
  <MIcon :path="mdiAccountPlusOutline" :size="18" />
  新增成员
</MButton>
```
:::

::: warning 节流不是防抖
默认 `throttle = 200`，意味着 200ms 内的连续点击会被丢弃。如果业务上确实需要「每次点击都有响应」，显式传 `:throttle="0"`。
:::

::: warning 组内变体会被父级覆盖
把 `MButton` 放进 `MButtonGroup` 后，`variant` 与 `size` 会被组的同名属性覆盖（`color` 仅在自身未设置时才取组值），这是为了避免组内按钮外观不一致。
:::

## 相关组件

- [ButtonGroup 按钮组](/components/button-group)：把多个 `MButton` 拼成一个整体。
- [Icon 图标](/components/icon)：按钮里的图标来自 `@mdi/js`。
