usePopup
提供 Telegram 原生弹窗功能的 Hook,让你在 Mini App 中显示原生样式的对话框。
导入
typescript
import { usePopup } from '@xcloud/ui-telegram';示例
API
返回值
| 属性 | 类型 | 描述 |
|---|---|---|
| show | (options: PopupOptions) => Promise<string | undefined> | 显示自定义弹窗 |
| confirm | (options: Omit<PopupOptions, 'buttons'>) => Promise<boolean> | 显示确认对话框 |
| alert | (options: Omit<PopupOptions, 'buttons'>) => Promise<void> | 显示提示对话框 |
| isAvailable | () => boolean | 检查 Popup 是否可用 |
PopupOptions
| 属性 | 类型 | 必填 | 描述 |
|---|---|---|---|
| title | string | 否 | 弹窗标题 |
| message | string | 是 | 弹窗消息内容 |
| buttons | PopupButton[] | 否 | 自定义按钮列表(最多3个) |
PopupButton
| 属性 | 类型 | 必填 | 描述 |
|---|---|---|---|
| id | string | 是 | 按钮的唯一标识 |
| type | 'default' | 'destructive' | 'cancel' | 是 | 按钮类型 |
| text | string | 是 | 按钮文本 |
使用示例
提示对话框
显示简单的提示信息:
tsx
import { usePopup } from '@xcloud/ui-telegram';
function SuccessMessage() {
const { alert } = usePopup();
const handleSuccess = async () => {
await alert({
title: '成功',
message: '你的操作已成功完成!',
});
};
return <button onClick={handleSuccess}>显示成功消息</button>;
}确认对话框
用户确认操作:
tsx
import { usePopup } from '@xcloud/ui-telegram';
function DeleteButton() {
const { confirm } = usePopup();
const handleDelete = async () => {
const confirmed = await confirm({
title: '确认删除',
message: '确定要删除这个项目吗?此操作无法撤销。',
});
if (confirmed) {
// 执行删除操作
await deleteItem();
}
};
return <button onClick={handleDelete}>删除</button>;
}自定义按钮
显示最多3个自定义按钮:
tsx
import { usePopup } from '@xcloud/ui-telegram';
function DocumentActions() {
const { show } = usePopup();
const handleActions = async () => {
const buttonId = await show({
title: '文档操作',
message: '请选择要执行的操作',
buttons: [
{ id: 'download', type: 'default', text: '下载' },
{ id: 'share', type: 'default', text: '分享' },
{ id: 'delete', type: 'destructive', text: '删除' },
],
});
switch (buttonId) {
case 'download':
downloadDocument();
break;
case 'share':
shareDocument();
break;
case 'delete':
deleteDocument();
break;
}
};
return <button onClick={handleActions}>文档操作</button>;
}处理用户取消
用户可能关闭弹窗而不点击任何按钮:
tsx
import { usePopup } from '@xcloud/ui-telegram';
function SaveChanges() {
const { show } = usePopup();
const handleSave = async () => {
const buttonId = await show({
title: '保存更改',
message: '是否保存你的更改?',
buttons: [
{ id: 'save', type: 'default', text: '保存' },
{ id: 'discard', type: 'destructive', text: '放弃' },
{ id: 'cancel', type: 'cancel', text: '取消' },
],
});
if (!buttonId) {
// 用户关闭了弹窗
console.log('User closed popup without selecting');
return;
}
if (buttonId === 'save') {
await saveChanges();
} else if (buttonId === 'discard') {
discardChanges();
}
// cancel 不做任何操作
};
return <button onClick={handleSave}>保存</button>;
}错误提示
显示错误信息并记录日志:
tsx
import { usePopup } from '@xcloud/ui-telegram';
function FormSubmit() {
const { alert } = usePopup();
const handleSubmit = async (data) => {
try {
await submitForm(data);
} catch (error) {
await alert({
title: '提交失败',
message: error.message || '请稍后重试',
});
console.error('Form submission failed:', error);
}
};
return <form onSubmit={handleSubmit}>...</form>;
}长文本消息
显示较长的文本内容:
tsx
import { usePopup } from '@xcloud/ui-telegram';
function TermsOfService() {
const { show } = usePopup();
const showTerms = async () => {
const accepted = await show({
title: '使用条款',
message: `
欢迎使用我们的服务。使用本服务即表示您同意以下条款:
1. 您必须遵守所有适用的法律法规
2. 不得滥用服务或干扰其他用户
3. 我们保留随时修改服务的权利
4. 您的数据将根据隐私政策处理
请仔细阅读并理解这些条款。
`.trim(),
buttons: [
{ id: 'accept', type: 'default', text: '接受' },
{ id: 'decline', type: 'destructive', text: '拒绝' },
],
});
return accepted === 'accept';
};
return <button onClick={showTerms}>查看条款</button>;
}支付确认
在支付前确认订单:
tsx
import { usePopup } from '@xcloud/ui-telegram';
function CheckoutButton({ total, items }: { total: number; items: number }) {
const { show } = usePopup();
const handleCheckout = async () => {
const confirmed = await show({
title: '确认订单',
message: `你将支付 $${total.toFixed(2)} 购买 ${items} 件商品。`,
buttons: [
{ id: 'pay', type: 'default', text: '确认支付' },
{ id: 'cancel', type: 'cancel', text: '取消' },
],
});
if (confirmed === 'pay') {
// 跳转到支付页面
proceedToPayment();
}
};
return (
<button onClick={handleCheckout}>
结账 (${total.toFixed(2)})
</button>
);
}评分请求
请求用户评分:
tsx
import { usePopup } from '@xcloud/ui-telegram';
function RatingPrompt() {
const { show } = usePopup();
const requestRating = async () => {
const response = await show({
title: '喜欢这个应用吗?',
message: '如果你喜欢这个应用,请给我们评分!',
buttons: [
{ id: 'rate', type: 'default', text: '去评分' },
{ id: 'later', type: 'default', text: '稍后提醒' },
{ id: 'never', type: 'cancel', text: '不再提醒' },
],
});
if (response === 'rate') {
openRatingPage();
} else if (response === 'later') {
scheduleReminderLater();
} else if (response === 'never') {
disableRatingPrompts();
}
};
return <button onClick={requestRating}>评分</button>;
}检查可用性
在非 Telegram 环境中降级处理:
tsx
import { usePopup } from '@xcloud/ui-telegram';
function NotificationButton() {
const { show, isAvailable } = usePopup();
const notify = async (message: string) => {
if (isAvailable()) {
await show({
title: '通知',
message,
buttons: [{ id: 'ok', type: 'default', text: '确定' }],
});
} else {
// 降级到浏览器 alert
alert(message);
}
};
return <button onClick={() => notify('Hello!')}>通知</button>;
}按钮类型说明
default
- 默认样式的按钮
- 通常用于确认、继续等正面操作
- 蓝色外观(遵循 Telegram 主题)
destructive
- 破坏性操作按钮
- 用于删除、移除等不可逆操作
- 红色外观,警示作用
cancel
- 取消按钮
- 用于取消操作、返回等
- 灰色外观,较低优先级
最佳实践
1. 限制按钮数量
Telegram 原生弹窗最多支持 3 个按钮。建议:
- 1 个按钮:确认信息
- 2 个按钮:确认/取消
- 3 个按钮:主操作/次要操作/取消
2. 合理使用按钮类型
tsx
// ✅ 好的做法
await show({
title: '删除确认',
message: '确定要删除吗?',
buttons: [
{ id: 'delete', type: 'destructive', text: '删除' },
{ id: 'cancel', type: 'cancel', text: '取消' },
],
});
// ❌ 不好的做法
await show({
title: '删除确认',
message: '确定要删除吗?',
buttons: [
{ id: 'delete', type: 'default', text: '删除' }, // 应该用 destructive
{ id: 'cancel', type: 'default', text: '取消' }, // 应该用 cancel
],
});3. 提供清晰的消息
消息应该简洁明了,告诉用户发生了什么或需要做什么:
tsx
// ✅ 好的做法
await alert({
title: '上传成功',
message: '你的文件已成功上传到云端',
});
// ❌ 不好的做法
await alert({
title: '成功',
message: '操作完成', // 太模糊
});4. 使用快捷方法
对于简单的确认和提示,使用 confirm() 和 alert():
tsx
// ✅ 使用快捷方法
const confirmed = await confirm({
title: '确认',
message: '确定要继续吗?',
});
// ❌ 不必要的复杂代码
const buttonId = await show({
title: '确认',
message: '确定要继续吗?',
buttons: [
{ id: 'ok', type: 'default', text: '确定' },
{ id: 'cancel', type: 'cancel', text: '取消' },
],
});
const confirmed = buttonId === 'ok';5. 处理关闭情况
始终处理用户关闭弹窗的情况:
tsx
const buttonId = await show({
title: '选择操作',
message: '请选择',
buttons: [...],
});
if (!buttonId) {
// 用户关闭了弹窗,不做任何操作
return;
}
// 处理用户选择注意事项
- 弹窗是模态的,会阻塞用户交互直到关闭
- 在 Web 版 Telegram 中,弹窗可能降级为浏览器原生 alert/confirm
- 按钮文本应简短,避免过长导致显示问题
- 消息内容支持换行符
\n - 不要在弹窗中放置过多信息,保持简洁
- 弹窗会自动适配 Telegram 的主题颜色
相关 Hooks
- useHapticFeedback - 触觉反馈
- useInitData - 获取 Telegram 初始化数据