Badge 徽标

把未读数或者短标记钉在宿主元素的角上。

399+NEW
<script setup lang="ts">
  import { Bell, Mail, MessageSquare } from '@lucide/vue'
  import { Badge, IconButton, Inline } from '@hina-ui/vue'
</script>

<template>
  <Inline align="center" class="gap-6">
    <Badge :content="3">
      <IconButton label="通知" variant="soft">
        <Bell />
      </IconButton>
    </Badge>
    <Badge :content="128" tone="accent">
      <IconButton label="私信" variant="soft">
        <Mail />
      </IconButton>
    </Badge>
    <Badge content="NEW" tone="success" size="md">
      <IconButton label="评论" variant="soft">
        <MessageSquare />
      </IconButton>
    </Badge>
  </Inline>
</template>
vue

用法

import { Badge } from '@hina-ui/vue'
ts

宿主元素放在默认插槽中,content 是钉在角上的内容。组件只负责定位与呈现,宿主本身不受影响。角标默认不接收指针事件,覆盖在宿主范围内的区域仍由宿主响应。

55 条未读
<script setup lang="ts">
  import { Bell } from '@lucide/vue'
  import { Badge, IconButton } from '@hina-ui/vue'
</script>

<template>
  <Badge :content="5" label="5 条未读">
    <IconButton label="通知" variant="soft">
      <Bell />
    </IconButton>
  </Badge>
</template>
vue

示例

最大值

content 为数字且超过 max 时显示为上限加号,默认上限为 99。

9999+999+
<script setup lang="ts">
  import { Bell } from '@lucide/vue'
  import { Badge, IconButton, Inline } from '@hina-ui/vue'
</script>

<template>
  <Inline align="center" class="gap-6">
    <Badge :content="99">
      <IconButton label="通知" variant="soft">
        <Bell />
      </IconButton>
    </Badge>
    <Badge :content="1280">
      <IconButton label="通知" variant="soft">
        <Bell />
      </IconButton>
    </Badge>
    <Badge :content="1280" :max="999">
      <IconButton label="通知" variant="soft">
        <Bell />
      </IconButton>
    </Badge>
  </Inline>
</template>
vue

色调

默认为 danger。未读与待办用 danger,一般计数用 accent 或者 neutral,状态提示按语义选择其余三种。

666666
<script setup lang="ts">
  import { Bell } from '@lucide/vue'
  import { Badge, IconButton, Inline } from '@hina-ui/vue'
</script>

<template>
  <Inline align="center" class="gap-6">
    <Badge
      v-for="tone in ['danger', 'accent', 'neutral', 'success', 'warning', 'info'] as const"
      :key="tone"
      :content="6"
      :tone="tone"
    >
      <IconButton label="通知" variant="soft">
        <Bell />
      </IconButton>
    </Badge>
  </Inline>
</template>
vue

尺寸

两种尺寸的字号相同,区别在于徽标的高度与最小宽度。宿主较大或者内容为文字时使用 md。

88
<script setup lang="ts">
  import { Bell } from '@lucide/vue'
  import { Badge, IconButton, Inline } from '@hina-ui/vue'
</script>

<template>
  <Inline align="center" class="gap-6">
    <Badge :content="8" size="sm">
      <IconButton label="通知" variant="soft">
        <Bell />
      </IconButton>
    </Badge>
    <Badge :content="8" size="md">
      <IconButton label="通知" variant="soft">
        <Bell />
      </IconButton>
    </Badge>
  </Inline>
</template>
vue

位置

placement 指定钉在哪个角,共四个取值,默认为右上角。

2222
<script setup lang="ts">
  import { Bell } from '@lucide/vue'
  import { Badge, IconButton, Inline } from '@hina-ui/vue'
</script>

<template>
  <Inline align="center" class="gap-6">
    <Badge
      v-for="placement in ['top-end', 'top-start', 'bottom-end', 'bottom-start'] as const"
      :key="placement"
      :content="2"
      :placement="placement"
    >
      <IconButton label="通知" variant="soft">
        <Bell />
      </IconButton>
    </Badge>
  </Inline>
</template>
vue

圆形宿主

宿主是圆形时设置 shape="circle",角点向内收拢,徽标贴合圆弧而不是外接矩形的角。

星见书音4

rect

星见书音4

circle

<script setup lang="ts">
  import { Avatar, Badge, Inline, Stack, Text } from '@hina-ui/vue'
</script>

<template>
  <Inline align="start" class="gap-8">
    <Stack gap="xs" align="center">
      <Badge :content="4">
        <Avatar size="lg" src="/avatars/peek.webp" alt="星见书音" />
      </Badge>
      <Text tone="muted" size="sm">rect</Text>
    </Stack>
    <Stack gap="xs" align="center">
      <Badge :content="4" shape="circle">
        <Avatar size="lg" src="/avatars/peek.webp" alt="星见书音" />
      </Badge>
      <Text tone="muted" size="sm">circle</Text>
    </Stack>
  </Inline>
</template>
vue

自定义内容

content 插槽用于替换徽标的内容,例如放入一个图标。

徽标是否渲染仍然由 content 属性决定,因此使用插槽时 content 也要设置为非空值。此时应当通过 label 提供无障碍名称。

已完成
<script setup lang="ts">
  import { Bookmark, Check } from '@lucide/vue'
  import { Badge, IconButton } from '@hina-ui/vue'
</script>

<template>
  <Badge content="已完成" tone="success" size="md" label="已完成">
    <template #content>
      <Check class="size-3" />
    </template>
    <IconButton label="收藏" variant="soft">
      <Bookmark />
    </IconButton>
  </Badge>
</template>
vue

设置 bare 后徽标不绘制底色,也没有内边距,只负责定位与描边,尺寸由插槽内容决定。把 Indicator 放入插槽即可在头像角上显示状态点。

星见书音在线星离开
<script setup lang="ts">
  import { Avatar, Badge, Indicator, Inline } from '@hina-ui/vue'
</script>

<template>
  <Inline gap="lg">
    <Badge content="online" bare label="在线" placement="bottom-end" shape="circle">
      <template #content>
        <Indicator tone="success" size="lg" />
      </template>
      <Avatar src="/avatars/paper.webp" alt="星见书音" />
    </Badge>
    <Badge content="away" bare label="离开" placement="bottom-end" shape="circle">
      <template #content>
        <Indicator tone="warning" size="lg" />
      </template>
      <Avatar name="星见书音" />
    </Badge>
  </Inline>
</template>
vue

描边

outline 默认开启,徽标外侧带一圈与页面底色相同的描边,使它从宿主的边缘切出。宿主颜色较深时可以关闭。

99
<script setup lang="ts">
  import { Bell } from '@lucide/vue'
  import { Badge, IconButton, Inline } from '@hina-ui/vue'
</script>

<template>
  <Inline align="center" class="gap-6">
    <Badge :content="9">
      <IconButton label="通知" variant="solid" tone="accent" pill size="lg">
        <Bell />
      </IconButton>
    </Badge>
    <Badge :content="9" :outline="false">
      <IconButton label="通知" variant="solid" tone="accent" pill size="lg">
        <Bell />
      </IconButton>
    </Badge>
  </Inline>
</template>
vue

出现与消失

content 为 0、空字符串或者未设置时,徽标不渲染。出现与消失都带缩放淡入淡出。

22 条未读
<script setup lang="ts">
  import { ref } from 'vue'
  import { Bell } from '@lucide/vue'
  import { Badge, Button, IconButton, Inline } from '@hina-ui/vue'

  const count = ref(2)
</script>

<template>
  <Inline align="center" class="gap-6">
    <Badge :content="count" :label="`${count} 条未读`">
      <IconButton label="通知" variant="soft">
        <Bell />
      </IconButton>
    </Badge>
    <Inline align="center">
      <Button variant="outline" tone="neutral" size="sm" @click="count = Math.max(0, count - 1)">
        减少
      </Button>
      <Button variant="outline" tone="neutral" size="sm" @click="count += 1">增加</Button>
    </Inline>
  </Inline>
</template>
vue

无障碍

  • 徽标里的数字缺少上下文,应当通过 label 补充完整说法,例如“3 条未读”。该文字只供屏幕阅读器读取,不显示在界面上。
  • 组件不改变宿主的语义。宿主是按钮时,它仍然是一个按钮。

API

Props

属性
类型
默认值
说明
content
string | number | null
—
徽标的内容,为空时不渲染
max
number
99
数字内容的显示上限
tone
'danger' | 'accent' | 'neutral' | 'success' | 'warning' | 'info'
'danger'
语义色调
size
'sm' | 'md'
'sm'
尺寸
placement
'top-end' | 'top-start' | 'bottom-end' | 'bottom-start'
'top-end'
钉在哪个角
shape
'rect' | 'circle'
'rect'
宿主的形状
outline
boolean
true
是否描出与页面底色相同的边
bare
boolean
false
是否只定位不画底
label
string
—
供屏幕阅读器读取的完整说法
class
string
—
追加至外层容器的类名

Slots

插槽
说明
default
宿主元素
content
替换徽标的内容