Toast
- 自动关闭。
- 悬停、聚焦和窗口失焦时暂停关闭。
- 支持快捷键跳转到消息视口。
- 支持通过滑动手势关闭。
- 公开用于滑动手势动画的 CSS 变量。
- 可控或不可控。
安装
在命令行中安装组件。
$ npm add reka-ui结构
导入组件。
<script setup lang="ts">
import { ToastAction, ToastClose, ToastDescription, ToastProvider, ToastRoot, ToastTitle, ToastViewport } from 'reka-ui'
</script>
<template>
<ToastProvider>
<ToastRoot>
<ToastTitle />
<ToastDescription />
<ToastAction />
<ToastClose />
</ToastRoot>
<ToastViewport />
</ToastProvider>
</template>API 参考
Provider
包装消息提示和消息视口的提供者。它通常包装整个应用。
<!- @include: @/meta/ToastProvider.md ->
Viewport
消息提示出现的固定区域。用户可以通过快捷键跳转到此视口。你需要确保键盘用户能够发现此快捷键。
<!- @include: @/meta/ToastViewport.md ->
Root
自动关闭的消息提示。不应为了获取用户响应而保持打开状态。
<!- @include: @/meta/ToastRoot.md ->
| Data Attribute | Value |
|---|---|
[data-state] | "open" | "closed" |
[data-swipe] | "start" | "move" | "cancel" | "end" |
[data-swipe-direction] | "up" | "down" | "left" | "right" |
| CSS Variable | Description |
|---|---|
--reka-toast-swipe-move-x | 水平滑动时消息提示的偏移位置 |
--reka-toast-swipe-move-y | 垂直滑动时消息提示的偏移位置 |
--reka-toast-swipe-end-x | 水平滑动后消息提示的最终偏移位置 |
--reka-toast-swipe-end-y | 垂直滑动后消息提示的最终偏移位置 |
Portal
使用时会将要呈现的内容传送至 body 中。
<!- @include: @/meta/ToastPortal.md ->
Title
消息提示的可选标题
<!- @include: @/meta/ToastTitle.md ->
Description
消息提示的内容。
<!- @include: @/meta/ToastDescription.md ->
Action
一个可以安全忽略的操作,确保用户不会因时间限制而执行具有意外副作用的操作。
当需要获取用户响应时,应改为向视口中传送一个样式化为消息提示的“AlertDialog”。
<!- @include: @/meta/ToastAction.md ->
Close
允许用户在消息提示持续时间内提前将其关闭的按钮。
<!- @include: @/meta/ToastClose.md ->
示例
自定义快捷键
使用 keycode.info 中每个键的 event.code 值覆盖默认快捷键。
<template>
<ToastProvider>
...
<ToastViewport :hotkey="['altKey', 'KeyT']" />
</ToastProvider>
</template>自定义持续时间
自定义消息提示的持续时间以覆盖提供者值。
<template>
<ToastRoot :duration="3000">
<ToastDescription>已保存!</ToastDescription>
</ToastRoot>
</template>重复消息提示
当用户每次点击按钮都必须显示消息提示时,使用状态渲染同一消息提示的多个实例(见下文)。或者,你可以抽象各个部分以创建自己的命令式 API。
<template>
<div>
<form @submit="count++">
...
<button>保存</button>
</form>
<ToastRoot v-for="(_, index) in count" :key="index">
<ToastDescription>已保存!</ToastDescription>
</ToastRoot>
</div>
</template>动画滑动手势
将 --reka-toast-swipe-move-[x|y] 和 --reka-toast-swipe-end-[x|y] CSS 变量与 data-swipe="[start|move|cancel|end]" 属性结合使用,以动画方式实现滑动关闭手势。以下是一个示例:
<template>
<ToastProvider swipe-direction="right">
<ToastRoot class="ToastRoot">
...
</ToastRoot>
<ToastViewport />
</ToastProvider>
</template>/* styles.css */
.ToastRoot[data-swipe='move'] {
transform: translateX(var(--reka-toast-swipe-move-x));
}
.ToastRoot[data-swipe='cancel'] {
transform: translateX(0);
transition: transform 200ms ease-out;
}
.ToastRoot[data-swipe='end'] {
animation: slideRight 100ms ease-out;
}
@keyframes slideRight {
from {
transform: translateX(var(--reka-toast-swipe-end-x));
}
to {
transform: translateX(100%);
}
}可访问性
遵循 aria-live 要求。
敏感度
使用 type 属性控制屏幕阅读器对消息提示的敏感度。
对于用户操作产生的消息提示,选择 foreground。由后台任务生成的消息提示应使用 background。
前台
前台消息提示会立即播报。当前台消息提示出现时,辅助技术可能会选择清除先前排队的消息。尽量避免同时堆叠不同的前台消息提示。
后台
后台消息提示会在下一个合适的时机播报,例如,当屏幕阅读器读完当前句子时。它们不会清除排队的消息,因此如果过度使用,对于屏幕阅读器用户来说,在响应用户交互时可能会感觉到用户体验迟缓。
<template>
<ToastRoot type="foreground">
<ToastDescription>文件移除成功。</ToastDescription>
<ToastClose>关闭</ToastClose>
</ToastRoot>
<ToastRoot type="background">
<ToastDescription>我们刚刚发布了 Reka UI 2.0。</ToastDescription>
<ToastClose>关闭</ToastClose>
</ToastRoot>
</template>替代操作
在 Action 上使用 altText 属性,以指导屏幕阅读器用户以替代方式操作消息提示。
你可以将用户引导至应用中可永久操作的位置,或者实现自己的自定义快捷键逻辑。如果实现后者,请使用 foreground 类型立即播报,并增加持续时间以给用户充足的时间。
<template>
<ToastRoot type="background">
<ToastTitle>有可用更新!</ToastTitle>
<ToastDescription>我们刚刚发布了 Reka UI 2.0。</ToastDescription>
<ToastAction alt-text="前往账户设置进行升级">
升级
</ToastAction>
<ToastClose>关闭</ToastClose>
</ToastRoot>
<ToastRoot type="foreground" :duration="10000">
<ToastDescription>文件移除成功。</ToastDescription>
<ToastAction alt-text="撤销 (Alt+U)">
撤销 <kbd>Alt</kbd>+<kbd>U</kbd>
</ToastAction>
<ToastClose>关闭</ToastClose>
</ToastRoot>
</template>关闭图标按钮
当提供图标(或字体图标)时,请记得为屏幕阅读器用户正确标注。
<template>
<ToastRoot type="foreground">
<ToastDescription>已保存!</ToastDescription>
<ToastClose aria-label="关闭">
<span aria-hidden="true">×</span>
</ToastClose>
</ToastRoot>
</template>键盘交互
| Key | Description |
|---|---|
F8 | 聚焦到消息提示视口。 |
Tab | 将焦点移动到下一个可聚焦元素。 |
Shift + Tab | 将焦点移动到上一个可聚焦元素。 |
Space |
当焦点位于 ToastAction 或
ToastClose 上时,关闭消息提示
|
Enter |
当焦点位于 ToastAction 或
ToastClose 上时,关闭消息提示
|
Esc |
当焦点位于 Toast 上时,关闭消息提示
|
自定义 API
抽象部分
通过将基本部分抽象到你自己的组件中来创建你自己的 API。
用法
<script setup lang="ts">
import Toast from './your-toast.vue'
</script>
<template>
<Toast
title="有可用更新"
content="我们刚刚发布了 Radix 3.0!"
>
<button @click="handleUpgrade">
升级
</button>
</Toast>
</template>实现
// your-toast.vue
<script setup lang="ts">
import { ToastAction, ToastClose, ToastDescription, ToastRoot, ToastTitle } from 'reka-ui'
defineProps<{
title: string
content: string
}>()
</script>
<template>
<ToastRoot>
<ToastTitle v-if="title">
{{ title }}
</ToastTitle>
<ToastDescription v-if="content">
{{ content }}
</ToastDescription>
<ToastAction
as-child
alt-text="toast"
>
<slot />
</ToastAction>
<ToastClose aria-label="关闭">
<span aria-hidden="true">×</span>
</ToastClose>
</ToastRoot>
</template>命令式 API
创建你自己的命令式 API,以便在需要时允许消息提示重复。
用法
<script setup lang="ts">
import Toast from './your-toast.vue'
const savedRef = ref<InstanceType<typeof Toast>>()
</script>
<template>
<div>
<form @submit="savedRef.publish()">
...
</form>
<Toast ref="savedRef">
保存成功!
</Toast>
</div>
</template>实现
// your-toast.vue
<script setup lang="ts">
import { ToastClose, ToastDescription, ToastRoot, ToastTitle } from 'reka-ui'
import { ref } from 'vue'
const count = ref(0)
function publish() {
count.value++
}
defineExpose({
publish
})
</script>
<template>
<ToastRoot
v-for="index in count"
:key="index"
>
<ToastDescription>
<slot />
</ToastDescription>
<ToastClose>关闭</ToastClose>
</ToastRoot>
</template>