Toast
轻提示,命令式调用为主
轻提示(Toast)在屏幕中央或上下方浮出一条短反馈。主用法是命令式函数(showToast 等),面板通过 Portal 挂载(zIndex 1000),因此在任意位置调用都能盖在页面之上。
import { showToast, showSuccessToast, showFailToast, showLoadingToast, closeToast } from '@skyroc/native-ui';命令式调用依赖 PortalHost,请确保 App 内已经挂了它。
类型
type 决定内置图标:text(无图标)、success(勾)、fail(叉)、loading(转圈)。四个快捷函数分别对应这些类型,参数可以直接传字符串(等价于 { message })。
import { Button, closeToast, showFailToast, showLoadingToast, showSuccessToast, showToast } from '@skyroc/native-ui';
import { View } from 'react-native';
const ToastTypes = () => {
return (
<View className="flex-row flex-wrap items-center gap-3 bg-background px-6 py-4">
<Button onPress={() => showToast('这是一条文字提示')}>文字</Button>
<Button onPress={() => showSuccessToast('操作成功')}>成功</Button>
<Button onPress={() => showFailToast('操作失败')}>失败</Button>
<Button onPress={() => showLoadingToast('加载中...')}>加载(常驻)</Button>
<Button
variant="outline"
onPress={closeToast}
>
关闭全部
</Button>
</View>
);
};
export { ToastTypes };loading 默认常驻(duration 为 0),需要手动 close() 或 update() 成其他类型。这个常驻是从 type 推导出来的,而不是写死 duration: 0 —— 所以 loading 被 update 成 success 后无需任何特判就会自然恢复成 2000ms 自动关闭。
何时使用
- 操作后的轻量反馈:保存成功、网络失败、加载中。
- 需要用户确认或有操作按钮时用
Dialog;系统级、贴边显示的横幅用Notify。
位置
position 支持 top / middle(默认)/ bottom。同一位置的多条 Toast 归入同一组纵向排列。
import type { ToastPosition } from '@skyroc/native-ui';
import { Button, showToast } from '@skyroc/native-ui';
import { View } from 'react-native';
const POSITIONS: ToastPosition[] = ['top', 'middle', 'bottom'];
const ToastPositions = () => {
return (
<View className="flex-row flex-wrap items-center gap-3 bg-background px-6 py-4">
{POSITIONS.map(position => (
<Button
key={position}
variant="tonal"
onPress={() => showToast({ message: position, position })}
>
{position}
</Button>
))}
</View>
);
};
export { ToastPositions };交互
duration:自动关闭延时(毫秒),0表示常驻;不传时loading为 0、其余类型为 2000。closeOnClick:点击 Toast 自身关闭。forbidClick:在 Toast 下方铺一层透明遮罩拦截触摸,屏蔽背景交互。
import { Button, showToast } from '@skyroc/native-ui';
import { View } from 'react-native';
const ToastInteraction = () => {
function handleManualClose() {
const instance = showToast({ duration: 0, message: '常驻,2 秒后由代码关闭' });
setTimeout(() => instance.close(), 2000);
}
return (
<View className="flex-row flex-wrap items-center gap-3 bg-background px-6 py-4">
<Button
variant="tonal"
onPress={() => showToast({ closeOnClick: true, duration: 0, message: '点我关闭' })}
>
点击关闭
</Button>
<Button
variant="tonal"
onPress={() => showToast({ forbidClick: true, message: '背景已被遮罩拦截', position: 'top' })}
>
禁止背景点击
</Button>
<Button
variant="tonal"
onPress={handleManualClose}
>
常驻 + 命令式关闭
</Button>
</View>
);
};
export { ToastInteraction };遮罩单独成一层铺满全屏,而不是复用定位容器 —— top / bottom 的定位容器只占一条,拿它拦触摸挡不住整屏。
生命周期
showToast 返回一个实例,带 close() 与 update(options):update 原地更新同一实例,不重新创建。onClose 在超时关闭、点击关闭、命令式关闭三条路径下都只触发一次。
import { Button, Text, allowMultipleToast, showLoadingToast, showToast } from '@skyroc/native-ui';
import { useState } from 'react';
import { View } from 'react-native';
const ToastLifecycle = () => {
const [closeCount, setCloseCount] = useState(0);
function handleCountedToast() {
showToast({
message: '关闭时计数 +1',
onClose: () => setCloseCount(prev => prev + 1)
});
}
function handleLoadingThenSuccess() {
const instance = showLoadingToast('上传中...');
setTimeout(() => {
// loading 常驻是从 type 推导的,改成 success 后自动恢复 2 秒关闭,无需再传 duration
instance.update({ message: '上传成功', type: 'success' });
}, 1500);
}
function handleMultiple() {
allowMultipleToast(true);
showToast({ message: '第一条', position: 'top' });
showToast({ message: '第二条', position: 'top' });
showToast({ message: '第三条', position: 'top' });
allowMultipleToast(false);
}
return (
<View className="bg-background px-6 py-4">
<View className="mb-2 flex-row flex-wrap items-center gap-3">
<Button
variant="tonal"
onPress={handleLoadingThenSuccess}
>
loading → success
</Button>
<Button
variant="tonal"
onPress={handleCountedToast}
>
onClose 计数
</Button>
<Button
variant="tonal"
onPress={handleMultiple}
>
同时显示多条
</Button>
</View>
<Text color="muted">onClose 已触发 {closeCount} 次(每关闭一次只应 +1)</Text>
</View>
);
};
export { ToastLifecycle };默认同一时刻只显示一条(新的会顶掉旧的)。需要并存时调用 allowMultipleToast(true),用完记得关掉。
自定义图标与样式
icon 覆盖内置图标,className / classNames 覆盖样式:
| slot | 作用位置 |
|---|---|
root | 提示卡片本体(底色、圆角、内边距) |
icon | 图标容器 |
message | 消息文字 |
import { Button, Text, showToast } from '@skyroc/native-ui';
import { View } from 'react-native';
const ToastCustom = () => {
return (
<View className="flex-row flex-wrap items-center gap-3 bg-background px-6 py-4">
<Button
variant="tonal"
onPress={() =>
showToast({
icon: <Text className="text-3xl">🎉</Text>,
message: '自定义图标'
})
}
>
Emoji 图标
</Button>
<Button
variant="tonal"
onPress={() =>
showToast({
className: 'rounded-none bg-primary',
classNames: { message: 'text-base text-primary-foreground' },
message: 'className 覆盖'
})
}
>
className 覆盖
</Button>
</View>
);
};
export { ToastCustom };有图标时卡片是 min-w-28 max-w-40 的方块,无图标时是 max-w-[85%] 的单行条 —— 两者的内边距也不同。
声明式用法
<Toast> 组件就地渲染,由 show 控制显隐、onUpdateShow 通知外部(组件到点后只通知,真正的隐藏仍由调用方改 show 完成)。
import { Button, Toast } from '@skyroc/native-ui';
import { useState } from 'react';
import { View } from 'react-native';
const ToastDeclarative = () => {
const [declarativeShow, setDeclarativeShow] = useState(false);
return (
<View className="bg-background px-6 py-4">
<View className="flex-row flex-wrap items-center gap-3">
<Button
variant="outline"
onPress={() => setDeclarativeShow(true)}
>
显示受控 Toast
</Button>
</View>
<View className="items-center">
<Toast
message="受控 Toast,2 秒后自动关闭"
show={declarativeShow}
type="success"
onUpdateShow={setDeclarativeShow}
/>
</View>
</View>
);
};
export { ToastDeclarative };声明式与命令式共用同一份 duration 默认值规则,不会出现「showLoadingToast 常驻、<Toast type="loading" /> 却 2 秒消失」这类分叉。但 position 与 forbidClick 在声明式下不可用(类型上已排除):它就地渲染在你写下它的位置,贴屏定位与遮罩由命令式路径的渲染器承担。
全局默认配置
import { setToastDefaultOptions, resetToastDefaultOptions, allowMultipleToast } from '@skyroc/native-ui';
setToastDefaultOptions({ position: 'top' }); // 全局默认
setToastDefaultOptions('loading', { forbidClick: true }); // 按类型默认
resetToastDefaultOptions('loading'); // 重置某个类型
resetToastDefaultOptions(); // 全部重置合并优先级是「全局默认 < 类型默认 < 调用参数」。
API
命令式函数
function showToast(options: ToastOptions | string): ToastInstance;
function showSuccessToast(options: ToastOptions | string): ToastInstance;
function showFailToast(options: ToastOptions | string): ToastInstance;
function showLoadingToast(options: ToastOptions | string): ToastInstance;
function closeToast(): void;
function allowMultipleToast(value?: boolean): void;
function setToastDefaultOptions(options: ToastOptions): void;
function setToastDefaultOptions(type: ToastType, options: ToastOptions): void;
function resetToastDefaultOptions(type?: ToastType): void;ToastOptions
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| message | 消息内容,字符串会自动包一层 Text | ReactNode | - |
| type | 类型,决定内置图标 | 'text' | 'success' | 'fail' | 'loading' | 'text' |
| position | 垂直位置 | 'top' | 'middle' | 'bottom' | 'middle' |
| duration | 自动关闭延时(毫秒),0 表示常驻;不传时 loading 为 0、其余为 2000 | number | - |
| icon | 自定义图标,覆盖内置图标 | ReactNode | - |
| closeOnClick | 是否允许点击 Toast 关闭 | boolean | false |
| forbidClick | 是否禁止背景点击(铺一层透明遮罩拦截触摸) | boolean | false |
| onClose | 关闭时回调,三条关闭路径都只触发一次 | () => void | - |
| className | 卡片本体类名,合并在 classNames.root 之后 | string | - |
| classNames | 各 slot 的类名覆盖 | SlotClassNames<ToastSlots> | - |
Toast
声明式组件,属性为 ToastOptions 去掉 position / forbidClick,另加:
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| show | 是否显示 | boolean | false |
| onUpdateShow | 显示状态变更回调(到点或点击关闭时触发) | (show: boolean) => void | - |
类型
import type { ToastInstance, ToastOptions, ToastPosition, ToastProps, ToastSlots, ToastType } from '@skyroc/native-ui';ToastType
提示类型,决定内置图标;loading 默认常驻。
ToastPosition
垂直位置。
ToastSlots
可通过 classNames 覆盖的 slot 名称。
SlotClassNames
classNames 的取值形态:把 slot 名映射到类名,每个 slot 都可选。本页用到的 slot 见 ToastSlots。
ToastInstance
showToast 系列函数的返回值。
| 字段 | 类型 | 说明 |
|---|---|---|
| close* | () => void | 关闭当前 Toast。 |
| update* | (options: ToastOptions) => void | 原地更新当前 Toast 的内容,保持同一实例、不重新创建。 |
包内还导出了 toastVariants、toastPositionVariants 与 ToastRenderer(由命令式路径自动挂载,一般不需要直接使用)。