# 列表项

## 使用方法

列表里的一行：有名字、有说明，前面能放点东西，后面也能放点东西，还能变成可以点的行。

```ts
import { ListItem } from '@astryx-vue/core/List'
```

它是 [列表](/components/list) 里的一行，渲染成一个 `<li>`。名字和说明直接写 `label` 和 `description`，前后各留一个插槽。默认它只是一行字，给它一件事做才会变成控件：加 `@click` 就变按钮，加 `href` 就变链接，加 `interactiveRef` 就指向行内那个本来就能操作的控件。

`ListItem` 是列表形状的入口，底下用的是通用的 [Item](/components/item)。行不在列表里时，直接用 `Item`。

## 示例

常见的用法和不同的状态。

### 基础

最朴素的列表行，一行名字一行说明。设置项、导航摘要这类简单列表都可以这样写。

```vue
<script setup lang="ts">
import { List, ListItem } from '@astryx-vue/core/List'
</script>

<template>
  <List header="Account settings" has-dividers>
    <ListItem label="Profile" description="Name, avatar, and bio" />
    <ListItem label="Notifications" description="Email and push alerts" />
    <ListItem label="Security" description="Password and two-factor auth" />
  </List>
</template>
```

### 带头像

前面带头像或图标的列表行。前面的东西要小，方便一眼扫过去。

```vue
<script setup lang="ts">
import { Avatar } from '@astryx-vue/core/Avatar'
import { Badge } from '@astryx-vue/core/Badge'
import { Icon } from '@astryx-vue/core/Icon'
import { List, ListItem } from '@astryx-vue/core/List'

function onSelect(): void {}
</script>

<template>
  <List header="Team" has-dividers>
    <ListItem label="Ada Lovelace" description="Design systems engineer" @click="onSelect">
      <template #startContent>
        <Avatar name="Ada Lovelace" size="sm" />
      </template>
      <template #endContent>
        <Badge label="Owner" variant="purple" />
      </template>
    </ListItem>
    <ListItem label="Grace Hopper" description="Platform infrastructure" @click="onSelect">
      <template #startContent>
        <Avatar name="Grace Hopper" size="sm" />
      </template>
      <template #endContent>
        <Badge label="On call" variant="blue" />
      </template>
    </ListItem>
    <ListItem label="Invite teammate" description="Send an invitation to collaborate" @click="onSelect">
      <template #startContent>
        <Icon icon="info" size="sm" color="secondary" />
      </template>
    </ListItem>
  </List>
</template>
```

### 带旁注

末尾对齐放一点信息。徽章、数量、时间、简短状态都可以放这里。

```vue
<script setup lang="ts">
import { Badge } from '@astryx-vue/core/Badge'
import { Icon } from '@astryx-vue/core/Icon'
import { List, ListItem } from '@astryx-vue/core/List'
import { Text } from '@astryx-vue/core/Text'

function onSelect(): void {}
</script>

<template>
  <List header="Inbox" density="compact" has-dividers>
    <ListItem label="Launch checklist" description="3 tasks still need an owner" is-selected @click="onSelect">
      <template #startContent>
        <Icon icon="check" size="sm" color="success" />
      </template>
      <template #endContent>
        <Badge label="3" variant="blue" />
      </template>
    </ListItem>
    <ListItem label="Security review" description="Waiting on approval" @click="onSelect">
      <template #startContent>
        <Icon icon="warning" size="sm" color="warning" />
      </template>
      <template #endContent>
        <Text color="secondary">
          Yesterday
        </Text>
      </template>
    </ListItem>
    <ListItem label="Old incident report" description="Archived and read-only" is-disabled>
      <template #startContent>
        <Icon icon="copy" size="sm" color="secondary" />
      </template>
      <template #endContent>
        <Text color="secondary">
          Apr 12
        </Text>
      </template>
    </ListItem>
  </List>
</template>
```

## 属性

| 属性 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `label` | `string \| number` | — | 这一行的主文字。写字符串或数字时只显示一行，超出用省略号；要放别的内容就用 `label` 插槽。 |
| `description` | `string \| number` | — | 主文字下面那行小字，同样只显示一行。要多行或者放别的内容就用 `description` 插槽。 |
| `density` | `ItemDensity`（`'compact' \| 'balanced' \| 'spacious'`） | 继承外面列表的值 | 盖掉外层 `List` 的疏密。不在列表里时默认是 `'balanced'`。 |
| `onClick` | `(event: MouseEvent) => void` | — | 点了之后做什么。给了它就渲染一个铺满行内容区的按钮，悬停和按下的样式也跟着有。模板里写 `@click`。 |
| `interactiveRef` | `MaybeRefOrGetter` | — | 指向行里那个本来就能操作的控件，比如 `startContent` 里的复选框。这时整行变成更大的点击区域，点行面就转给那个控件，行自己不再渲染按钮，也就不会多一个 Tab 停留点。它和 `onClick`、`href` 只能用一个，写了它那两个会被忽略。 |
| `href` | `string` | — | 链接地址。行里会渲染一个链接元素。 |
| `target` | `'_blank' \| '_self'` | — | 链接在哪打开，只有写了 `href` 才有用。`_blank` 会自动补上 `noopener` 和 `noreferrer`。 |
| `rel` | `string` | — | 链接的 rel 值，会和自动补的那些合在一起。 |
| `isDisabled` | `boolean` | `false` | 禁用。这一行不动了，内容变淡，同时写上 `aria-disabled="true"`。 |
| `isSelected` | `boolean` | `false` | 选中状态。行的角色支持时写成 `aria-selected="true"`，不支持时写成 `aria-current="true"`。你自己传的 `aria-current` 优先。 |
| `swipeActions` | `ItemSwipeActions` | — | 手指横滑能露出哪些操作，左右各一组，每项是 `{ label, icon?, onActivate, isDisabled?, variant?, hasRemoval? }`。鼠标不会触发这次拖动。每个操作都要在行里再有个入口，否则键盘和鼠标用户够不着。 |
| `swipeBehavior` | `'reveal' \| 'commit'` | `'reveal'` | `reveal` 松手后行停在滑开的位置，拖得够远就触发最外面那个操作；`commit` 直接把行滑出去，松手就触发，什么都不留在屏幕上。 |

## 插槽

- `startContent`：名字前面，比如图标或头像。
- `label`：自己画主文字，替掉 `label` 属性。
- `description`：自己画说明，替掉 `description` 属性。
- `endContent`：名字后面，比如徽章、数量、时间。

## 暴露

`element`（根元素）、`focus()` 和 `blur()`。聚焦会落到行里那个真正能接焦点的控件上。
