Compare commits

...
10 Commits
16 changed files with 21834 additions and 237 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 thzxx
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+16
View File
@@ -46,6 +46,22 @@ const MeToast = require('metona-toast');
</script> </script>
``` ```
## 环境与版本支持
| 环境 | 最低版本 |
|------|---------|
| Chrome | 64+ |
| Firefox | 63+ |
| Safari | 11+ |
| Edge | 79+ |
| Opera | 51+ |
| iOS Safari | 11+ |
| Android Chrome | 64+ |
| Node.js | 18+ESM & CJS 双格式) |
| TypeScript | 4.5+(完整类型声明) |
核心依赖:Web Animations APIChrome 64+, Firefox 63+, Safari 11+)、Pointer Events、CSS Grid、CSS Custom Properties。
## 快速开始 ## 快速开始
浏览器中 `window` 上会注册两个全局变量:`MeToast``Met`,两者完全等价,任选其一使用。 浏览器中 `window` 上会注册两个全局变量:`MeToast``Met`,两者完全等价,任选其一使用。
+6712
View File
File diff suppressed because it is too large Load Diff
+1
View File
File diff suppressed because one or more lines are too long
+1082
View File
File diff suppressed because it is too large Load Diff
+6703
View File
File diff suppressed because it is too large Load Diff
+1
View File
File diff suppressed because one or more lines are too long
+6718
View File
File diff suppressed because it is too large Load Diff
+1
View File
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
+2
View File
@@ -4,6 +4,8 @@
"description": "轻量、零依赖、精致美观的Toast通知库。单文件,开箱即用。", "description": "轻量、零依赖、精致美观的Toast通知库。单文件,开箱即用。",
"main": "dist/metona-toast.js", "main": "dist/metona-toast.js",
"module": "src/index.js", "module": "src/index.js",
"unpkg": "dist/metona-toast.min.js",
"jsdelivr": "dist/metona-toast.min.js",
"types": "types/index.d.ts", "types": "types/index.d.ts",
"exports": { "exports": {
".": { ".": {
+256 -98
View File
@@ -3,6 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<title>在线演示 — MetonaToast</title> <title>在线演示 — MetonaToast</title>
<style> <style>
:root { :root {
@@ -20,27 +21,28 @@
.nav-links { display:flex; gap:20px; } .nav-links { display:flex; gap:20px; }
.nav-links a { color:var(--muted); font-size:13px; font-weight:500; transition:.2s; } .nav-links a { color:var(--muted); font-size:13px; font-weight:500; transition:.2s; }
.nav-links a:hover { color:var(--accent2); } .nav-links a:hover { color:var(--accent2); }
.hero { text-align:center; padding:50px 20px 40px; border-bottom:1px solid var(--border); background:radial-gradient(ellipse at 50% 0%,rgba(99,102,241,0.12) 0%,transparent 50%); } .hero { text-align:center; padding:40px 20px 30px; border-bottom:1px solid var(--border); background:radial-gradient(ellipse at 50% 0%,rgba(99,102,241,0.12) 0%,transparent 50%); }
.hero h1 { font-size:36px; font-weight:800; } .hero h1 { font-size:36px; font-weight:800; }
.hero h1 span { background:linear-gradient(135deg,#818cf8,#c084fc,#f472b6); -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text; } .hero h1 span { background:linear-gradient(135deg,#818cf8,#c084fc,#f472b6); -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text; }
.hero p { color:var(--muted); font-size:14px; margin-top:6px; } .hero p { color:var(--muted); font-size:14px; margin-top:6px; }
.container { max-width:1300px; margin:0 auto; padding:32px 20px; display:grid; grid-template-columns:repeat(auto-fill,minmax(380px,1fr)); gap:20px; } .container { max-width:1300px; margin:0 auto; padding:24px 20px; display:grid; grid-template-columns:repeat(auto-fill,minmax(400px,1fr)); gap:18px; }
.card { background:var(--surface); border:1px solid var(--border); border-radius:var(--radius); padding:22px; } .card { background:var(--surface); border:1px solid var(--border); border-radius:var(--radius); padding:20px; }
.card h2 { font-size:16px; margin-bottom:4px; } .card h2 { font-size:15px; margin-bottom:2px; }
.card > p { color:var(--muted); font-size:12px; margin-bottom:14px; } .card > p { color:var(--muted); font-size:11px; margin-bottom:12px; }
.btn-row { display:flex; flex-wrap:wrap; gap:7px; } .btn-row { display:flex; flex-wrap:wrap; gap:6px; }
.btn { padding:8px 15px; border:none; border-radius:7px; font-size:12px; font-weight:500; cursor:pointer; transition:.15s; color:#fff; } .btn { padding:8px 14px; border:none; border-radius:7px; font-size:12px; font-weight:500; cursor:pointer; transition:.15s; color:#fff; }
.btn:hover { transform:translateY(-1px); filter:brightness(1.15); } .btn:hover { transform:translateY(-1px); filter:brightness(1.15); }
.btn-sm { padding:5px 10px; font-size:11px; border-radius:5px; } .btn-sm { padding:5px 10px; font-size:11px; border-radius:5px; }
.btn-outline { background:transparent; border:1px solid var(--border); color:var(--text); } .btn-outline { background:transparent; border:1px solid var(--border); color:var(--text); }
.btn-outline:hover { border-color:var(--accent); background:rgba(99,102,241,0.06); } .btn-outline:hover { border-color:var(--accent); background:rgba(99,102,241,0.06); }
.btn-tiny { padding:4px 9px; font-size:10px; border-radius:4px; }
.c-s { background:#10b981; } .c-e { background:#ef4444; } .c-w { background:#f59e0b; color:#1e293b; } .c-s { background:#10b981; } .c-e { background:#ef4444; } .c-w { background:#f59e0b; color:#1e293b; }
.c-i { background:#3b82f6; } .c-p { background:#6366f1; } .c-pp { background:#8b5cf6; } .c-i { background:#3b82f6; } .c-p { background:#6366f1; } .c-pp { background:#8b5cf6; }
.c-pk { background:#ec4899; } .c-t { background:#14b8a6; } .c-o { background:#f97316; } .c-pk { background:#ec4899; } .c-t { background:#14b8a6; } .c-o { background:#f97316; }
.c-sl { background:#475569; } .c-r { background:#f43f5e; } .c-sl { background:#475569; } .c-r { background:#f43f5e; } .c-g { background:#22c55e; }
.label { font-size:10px; text-transform:uppercase; letter-spacing:0.8px; color:var(--muted); margin-bottom:12px; font-weight:600; } .label { font-size:10px; text-transform:uppercase; letter-spacing:0.8px; color:var(--muted); margin-bottom:10px; font-weight:600; }
.demo-section { border-top:1px solid var(--border); padding-top:10px; margin-top:10px; } .demo-section { border-top:1px solid var(--border); padding-top:8px; margin-top:8px; }
footer { text-align:center; padding:30px 20px; color:var(--muted); font-size:12px; border-top:1px solid var(--border); } footer { text-align:center; padding:30px 20px; color:var(--muted); font-size:12px; border-top:1px solid var(--border); }
@media (max-width:768px) { .container { grid-template-columns:1fr; } } @media (max-width:768px) { .container { grid-template-columns:1fr; } }
</style> </style>
@@ -61,12 +63,12 @@
<header class="hero"> <header class="hero">
<h1><span>在线演示</span></h1> <h1><span>在线演示</span></h1>
<p>所有功能均可点击体验 — 192 个测试用例全部通过验证</p> <p>覆盖项目全部功能的交互演示 — 点击即可体验</p>
</header> </header>
<main class="container"> <main class="container">
<!-- 基础通知 --> <!-- 1. 基础通知 -->
<div class="card"> <div class="card">
<div class="label">📢 基础通知</div> <div class="label">📢 基础通知</div>
<div class="btn-row"> <div class="btn-row">
@@ -79,181 +81,337 @@
<div class="demo-section"> <div class="demo-section">
<div class="btn-row"> <div class="btn-row">
<button class="btn btn-outline btn-sm" onclick="MeToast.success({title:'保存成功',message:'文件已同步到云端'})">带标题</button> <button class="btn btn-outline btn-sm" onclick="MeToast.success({title:'保存成功',message:'文件已同步到云端'})">带标题</button>
<button class="btn btn-outline btn-sm" onclick="MeToast.info('显示10秒',{duration:10000})">长时10s</button> <button class="btn btn-outline btn-sm" onclick="MeToast.info('持续10秒',{duration:10000})">长时10s</button>
<button class="btn btn-outline btn-sm" onclick="MeToast.info('手动关闭',{duration:0})">手动关闭</button> <button class="btn btn-outline btn-sm" onclick="MeToast.warning('手动关闭',{duration:0,closeButton:true})">手动关闭</button>
<button class="btn btn-outline btn-sm" onclick="MeToast.info('隐藏图标',{icon:false})">无图标</button> <button class="btn btn-outline btn-sm" onclick="MeToast.info('',{icon:false})">无图标</button>
<button class="btn btn-outline btn-sm" onclick="MeToast.info('隐藏进度条',{showProgress:false})">进度条</button> <button class="btn btn-outline btn-sm" onclick="MeToast.info('无按钮',{closeButton:false})">关闭按钮</button>
<button class="btn btn-outline btn-sm" onclick="demoCustomIcon()">自定义图标</button>
</div> </div>
</div> </div>
</div> </div>
<!-- Loading 链式 --> <!-- 2. Loading 链式 -->
<div class="card"> <div class="card">
<div class="label">🔄 Loading 链式转换</div> <div class="label">🔄 Loading 链式转换</div>
<div class="btn-row"> <div class="btn-row">
<button class="btn c-p" onclick="demoLoading()">提交成功</button> <button class="btn c-s" onclick="demoLoading()">提交成功</button>
<button class="btn c-e" onclick="demoLoadingFail()">提交失败</button> <button class="btn c-e" onclick="demoLoadingFail()">提交失败</button>
<button class="btn c-pp" onclick="demoPromise()">Promise 风格</button> <button class="btn c-w" onclick="demoLoadingWarn()">转为警告</button>
<button class="btn c-i" onclick="demoLoadingUpdate()">原地更新</button>
</div> </div>
</div> </div>
<!-- 对话框 --> <!-- 3. Promise + confirm + prompt -->
<div class="card"> <div class="card">
<div class="label">💬 对话框</div> <div class="label">💬 对话框</div>
<div class="btn-row"> <div class="btn-row">
<button class="btn c-pp" onclick="demoPromise()">Promise 风格</button>
<button class="btn c-pk" onclick="demoConfirm()">确认对话框</button> <button class="btn c-pk" onclick="demoConfirm()">确认对话框</button>
<button class="btn c-t" onclick="demoPrompt()">输入对话框</button> <button class="btn c-t" onclick="demoPrompt()">输入对话框</button>
<button class="btn c-o" onclick="demoCountdown()">倒计时 5s</button> <button class="btn c-o" onclick="demoPromptPassword()">密码输入</button>
</div> </div>
</div> </div>
<!-- 进度 & 队列 --> <!-- 4. 进度 & 倒计时 -->
<div class="card"> <div class="card">
<div class="label">📊 进度 & 队列</div> <div class="label">📊 进度 & 倒计时</div>
<div class="btn-row"> <div class="btn-row">
<button class="btn c-o" onclick="demoProgress()">进度条</button> <button class="btn c-o" onclick="demoProgress()">进度条(水平)</button>
<button class="btn c-p" onclick="demoQueue()">队列展示</button> <button class="btn c-g" onclick="demoProgressV()">进度条(垂直)</button>
<button class="btn c-pp" onclick="demoStack()">堆叠展示</button> <button class="btn c-pk" onclick="demoCountdown()">倒计时 5s</button>
<button class="btn c-r" onclick="demoCountdownPause()">倒计时(可暂停)</button>
</div> </div>
</div> </div>
<!-- Action Toast --> <!-- 5. 队列 & 堆叠 -->
<div class="card"> <div class="card">
<div class="label">⚡ Action Toast <span style="color:#34d399;font-size:10px;">NEW</span></div> <div class="label">📋 队列 & 堆叠</div>
<div class="btn-row">
<button class="btn c-p" onclick="demoQueue()">队列展示</button>
<button class="btn c-e" onclick="demoQueueCancel()">队列中途取消</button>
<button class="btn c-pp" onclick="demoStack()">堆叠展示</button>
<button class="btn c-t" onclick="demoStackMixed()">混合类型堆叠</button>
</div>
</div>
<!-- 6. Action Toast -->
<div class="card">
<div class="label">⚡ Action Toast <span style="color:#34d399;font-size:10px;">v2.0</span></div>
<div class="btn-row"> <div class="btn-row">
<button class="btn c-e" onclick="demoActionDelete()">删除+撤销</button> <button class="btn c-e" onclick="demoActionDelete()">删除+撤销</button>
<button class="btn c-i" onclick="demoActionMulti()">个操作</button> <button class="btn c-i" onclick="demoActionMulti()">按钮</button>
<button class="btn c-s" onclick="demoActionSuccess()">成功+查看</button> <button class="btn c-s" onclick="demoActionNoClose()">不自动关闭</button>
</div> </div>
</div> </div>
<!-- 分组管理 --> <!-- 7. 分组管理 -->
<div class="card"> <div class="card">
<div class="label">📁 分组管理 <span style="color:#34d399;font-size:10px;">NEW</span></div> <div class="label">📁 分组管理 <span style="color:#34d399;font-size:10px;">v2.0</span></div>
<div class="btn-row"> <div class="btn-row">
<button class="btn c-p" onclick="demoGroup()">创建分组</button> <button class="btn c-p" onclick="demoGroup()">创建分组消息</button>
<button class="btn c-e" onclick="dismissGroup()">关闭分组</button> <button class="btn c-e" onclick="dismissGroup()">关闭分组</button>
<button class="btn btn-outline btn-sm" onclick="MeToast.info('分组数量: '+group.count())">查看数量</button> <button class="btn c-i" onclick="MeToast.info('分组数量: '+group.count(),{type:'info'})">查看数量</button>
<button class="btn btn-outline btn-sm" onclick="demoGroupMixed()">混合类型分组</button>
</div> </div>
</div> </div>
<!-- 动画效果 --> <!-- 8. 动画效果 -->
<div class="card"> <div class="card">
<div class="label">🎭 动画效果</div> <div class="label">🎭 11种动画效果</div>
<div class="btn-row"> <div class="btn-row">
<button class="btn btn-outline btn-sm" onclick="anim('slide')">slide</button> <button class="btn btn-outline btn-tiny" onclick="anim('slide')">slide</button>
<button class="btn btn-outline btn-sm" onclick="anim('fade')">fade</button> <button class="btn btn-outline btn-tiny" onclick="anim('fade')">fade</button>
<button class="btn btn-outline btn-sm" onclick="anim('scale')">scale</button> <button class="btn btn-outline btn-tiny" onclick="anim('scale')">scale</button>
<button class="btn btn-outline btn-sm" onclick="anim('bounce')">bounce</button> <button class="btn btn-outline btn-tiny" onclick="anim('bounce')">bounce</button>
<button class="btn btn-outline btn-sm" onclick="anim('flip')">flip</button> <button class="btn btn-outline btn-tiny" onclick="anim('flip')">flip</button>
<button class="btn btn-outline btn-sm" onclick="anim('rotate')">rotate</button> <button class="btn btn-outline btn-tiny" onclick="anim('rotate')">rotate</button>
<button class="btn btn-outline btn-sm" onclick="anim('zoom')">zoom</button> <button class="btn btn-outline btn-tiny" onclick="anim('zoom')">zoom</button>
<button class="btn btn-outline btn-sm" onclick="anim('slideUp')">slideUp</button> <button class="btn btn-outline btn-tiny" onclick="anim('slideUp')">slideUp</button>
<button class="btn btn-outline btn-sm" onclick="anim('slideDown')">slideDown</button> <button class="btn btn-outline btn-tiny" onclick="anim('slideDown')">slideDown</button>
<button class="btn btn-outline btn-sm" onclick="anim('slideLeft')">slideLeft</button> <button class="btn btn-outline btn-tiny" onclick="anim('slideLeft')">slideLeft</button>
<button class="btn btn-outline btn-sm" onclick="anim('slideRight')">slideRight</button> <button class="btn btn-outline btn-tiny" onclick="anim('slideRight')">slideRight</button>
</div> </div>
</div> </div>
<!-- 位置 --> <!-- 9. 6种位置 -->
<div class="card"> <div class="card">
<div class="label">📍 位置</div> <div class="label">📍 全部位置</div>
<div class="btn-row"> <div class="btn-row">
<button class="btn c-sl" onclick="MeToast.success('左上角',{position:'top-left'})">↖ top-left</button> <button class="btn btn-outline btn-sm" onclick="MeToast.success('左上角',{position:'top-left'})">↖ top-left</button>
<button class="btn c-sl" onclick="MeToast.success('顶部居中',{position:'top-center'})">↑ top-center</button> <button class="btn btn-outline btn-sm" onclick="MeToast.success('顶部居中',{position:'top-center'})">↑ top-center</button>
<button class="btn c-sl" onclick="MeToast.success('右上角',{position:'top-right'})">↗ top-right</button> <button class="btn btn-outline btn-sm" onclick="MeToast.success('右上角',{position:'top-right'})">↗ top-right</button>
<button class="btn c-sl" onclick="MeToast.success('左下角',{position:'bottom-left'})">↙ bottom-left</button> <button class="btn btn-outline btn-sm" onclick="MeToast.success('左下角',{position:'bottom-left'})">↙ bottom-left</button>
<button class="btn c-sl" onclick="MeToast.success('底部居中',{position:'bottom-center'})">↓ bottom-center</button> <button class="btn btn-outline btn-sm" onclick="MeToast.success('底部居中',{position:'bottom-center'})">↓ bottom-center</button>
<button class="btn c-sl" onclick="MeToast.success('右下角',{position:'bottom-right'})">↘ bottom-right</button> <button class="btn btn-outline btn-sm" onclick="MeToast.success('右下角',{position:'bottom-right'})">↘ bottom-right</button>
</div> </div>
</div> </div>
<!-- 主题 --> <!-- 10. 主题切换 + 自定义 -->
<div class="card"> <div class="card">
<div class="label">🎨 主题切换</div> <div class="label">🎨 主题切换 & 自定义</div>
<div class="btn-row"> <div class="btn-row">
<button class="btn btn-outline btn-sm" onclick="switchTheme('light')">☀️ Light</button> <button class="btn btn-outline btn-sm" onclick="switchTheme('light')">☀️ Light</button>
<button class="btn btn-outline btn-sm" onclick="switchTheme('dark')">🌙 Dark</button> <button class="btn btn-outline btn-sm" onclick="switchTheme('dark')">🌙 Dark</button>
<button class="btn btn-outline btn-sm" onclick="switchTheme('auto')">🔄 Auto</button> <button class="btn btn-outline btn-sm" onclick="switchTheme('auto')">🔄 Auto</button>
<button class="btn btn-outline btn-sm" onclick="switchTheme('warm')">🔥 Warm</button> <button class="btn btn-outline btn-sm" onclick="switchTheme('warm')">🔥 Warm</button>
<button class="btn btn-outline btn-sm" onclick="demoRegisterTheme()">注册自定义主题</button>
</div> </div>
</div> </div>
<!-- 插件 --> <!-- 11. 插件系统 -->
<div class="card"> <div class="card">
<div class="label">🔌 插件</div> <div class="label">🔌 插件系统</div>
<div class="btn-row"> <div class="btn-row">
<button class="btn c-p" onclick="MeToast.use('keyboard');MeToast.info('已安装 — 试试按 ESC 键','keyboard插件')">keyboard ESC关闭</button> <button class="btn btn-outline btn-sm" onclick="MeToast.use('keyboard');MeToast.info('已安装 — 按 ESC 关闭所有 Toast')">keyboard ESC关闭</button>
<button class="btn c-i" onclick="MeToast.use('persistence');MeToast.info('已安装 — 配置将自动保存','persistence插件')">persistence 持久化</button> <button class="btn btn-outline btn-sm" onclick="MeToast.use('persistence');MeToast.info('已安装 — 配置将持久化到 localStorage')">persistence 持久化</button>
<button class="btn c-t" onclick="MeToast.use('accessibility');MeToast.info('已安装 — 屏幕阅读器可用','accessibility插件')">accessibility 无障碍</button> <button class="btn btn-outline btn-sm" onclick="MeToast.use('accessibility');MeToast.info('已安装 — 屏幕阅读器可用')">accessibility 无障碍</button>
<button class="btn btn-outline btn-sm" onclick="demoCustomPlugin()">自定义插件</button>
</div> </div>
</div> </div>
<!-- 管理 --> <!-- 12. v2.0 新功能 -->
<div class="card">
<div class="label">🆕 v2.0 新功能 <span style="color:#34d399;font-size:10px;">resetTimer · onUpdate · render · notify</span></div>
<div class="btn-row">
<button class="btn c-i" onclick="demoResetTimer()">resetTimerOnUpdate</button>
<button class="btn c-p" onclick="demoOnUpdate()">onUpdate 回调</button>
<button class="btn c-pp" onclick="demoCustomRender()">自定义渲染</button>
<button class="btn c-w" onclick="demoNotify()">系统通知</button>
</div>
</div>
<!-- 13. Toast 管理 -->
<div class="card"> <div class="card">
<div class="label">🔧 Toast 管理</div> <div class="label">🔧 Toast 管理</div>
<div class="btn-row"> <div class="btn-row">
<button class="btn c-s" onclick="MeToast.success('消息 '+(MeToast.count()+1))">发一条</button> <button class="btn c-s" onclick="MeToast.success('消息 '+(MeToast.count()+1))">发一条</button>
<button class="btn c-i" onclick="MeToast.info('消息 '+(MeToast.count()+1))">一条</button> <button class="btn c-i" onclick="MeToast.info('消息 '+(MeToast.count()+1))">再一条</button>
<button class="btn c-w" onclick="MeToast.info('当前 '+MeToast.count()+' 条消息')">查看数量</button> <button class="btn c-w" onclick="MeToast.info('当前 '+MeToast.count()+' 条')">查看数量</button>
<button class="btn c-sl" onclick="MeToast.pauseAll();MeToast.info('已暂停全部')">暂停全部</button>
<button class="btn c-sl" onclick="MeToast.resumeAll();MeToast.info('已恢复全部')">恢复全部</button>
<button class="btn c-e" onclick="MeToast.dismiss()">关闭全部</button> <button class="btn c-e" onclick="MeToast.dismiss()">关闭全部</button>
<button class="btn c-sl" onclick="MeToast.pauseAll();MeToast.info('已暂停全部计时')">暂停全部</button> <button class="btn c-r" onclick="MeToast.destroy();MeToast.info('已销毁')">销毁</button>
<button class="btn c-sl" onclick="MeToast.resumeAll();MeToast.info('已恢复全部计时')">恢复全部</button>
</div> </div>
<div class="demo-section">
<div class="btn-row">
<button class="btn btn-outline btn-tiny" onclick="demoFindById()">findById</button>
<button class="btn btn-outline btn-tiny" onclick="demoGetAll()">getAll</button>
<button class="btn btn-outline btn-tiny" onclick="demoClearByPos()">clear(位置)</button>
<button class="btn btn-outline btn-tiny" onclick="demoGetConfig()">查看配置</button>
</div>
</div>
</div>
<!-- 14. 交互特性 -->
<div class="card">
<div class="label">✋ 交互特性</div>
<div class="btn-row">
<button class="btn c-i" onclick="demoDraggable()">拖拽关闭</button>
<button class="btn c-p" onclick="demoPauseHover()">悬停暂停</button>
<button class="btn c-w" onclick="demoCloseOnClick()">点击关闭</button>
<button class="btn c-pp" onclick="demoWidth()">自定义宽度</button>
<button class="btn c-t" onclick="demoClassName()">自定义className</button>
</div>
</div>
<!-- 15. 国际化切换 -->
<div class="card">
<div class="label">🌍 国际化 & 格式化</div>
<div class="btn-row">
<button class="btn c-s" onclick="switchLocale('zh-CN')">切换到中文</button>
<button class="btn c-i" onclick="switchLocale('en-US')">Switch to English</button>
<button class="btn btn-outline btn-sm" onclick="demoFormat()">格式化演示</button>
</div>
</div>
<!-- 16. 107种预设图标 -->
<div class="card" style="grid-column:1/-1;">
<div class="label">🎨 107种预设图标 — 点击任意图标发送Toast</div>
<div class="btn-row" id="icon-grid" style="max-height:300px;overflow-y:auto;padding:4px 0;"></div>
</div> </div>
</main> </main>
<footer> <footer>
MetonaToast v2.0.0 · MIT License · <a href="index.html">首页</a> · <a href="docs.html">文档</a> MetonaToast v2.0.0 · MIT · <a href="index.html">首页</a> · <a href="docs.html">文档</a> · <a href="https://gitee.com/thzxx/MetonaToast">Gitee</a>
</footer> </footer>
<script src="../dist/metona-toast.js"></script> <script src="../dist/metona-toast.js"></script>
<script> <script>
MeToast.configure({ position:'top-right', duration:4000, theme:'dark', animation:'slide', pauseOnHover:true, showProgress:true }); MeToast.configure({ position:'top-right', duration:4000, theme:'dark', animation:'slide', pauseOnHover:true, showProgress:true });
// Loading // === Loading ===
function demoLoading() { const l=MeToast.loading('正在提交...'); setTimeout(()=>l.success('提交成功!'),2000); } function demoLoading() { const l=MeToast.loading('正在提交...'); setTimeout(()=>l.success('提交成功!'),2000); }
function demoLoadingFail() { const l=MeToast.loading('正在提交...'); setTimeout(()=>l.error('提交失败,请重试'),2000); } function demoLoadingFail() { const l=MeToast.loading('正在处理...'); setTimeout(()=>l.error('处理失败'),2000); }
function demoLoadingWarn() { const l=MeToast.loading('检查中...'); setTimeout(()=>l.warning('发现潜在问题'),2000); }
function demoLoadingUpdate() { const l=MeToast.loading('处理中 0%'); let i=1; const t=setInterval(()=>{if(i>3){clearInterval(t);l.success('完成!');return;} l.update({message:'处理中 '+i*33+'%'}); i++;},600); }
// === Promise / confirm / prompt ===
async function demoPromise() { async function demoPromise() {
const p=new Promise((r,e)=>setTimeout(()=>Math.random()>0.3?r('ok'):e('fail'),2000)); const p=new Promise((r,e)=>setTimeout(()=>Math.random()>0.3?r('ok'):e('fail'),2000));
try{await MeToast.promise(p,{loading:'处理中...',success:'成功!',error:'失败'});}catch(_){} try{await MeToast.promise(p,{loading:'处理中...',success:'成功!',error:'失败'});}catch(_){}
} }
async function demoConfirm() { const ok=await MeToast.confirm('确定删除?',{confirmText:'删除',confirmColor:'#ef4444'}); if(ok)MeToast.success('已删除'); }
// 对话框
async function demoConfirm() { const ok=await MeToast.confirm('确定删除吗?',{confirmText:'删除',confirmColor:'#ef4444'}); if(ok)MeToast.success('已删除'); else MeToast.info('已取消'); }
async function demoPrompt() { const v=await MeToast.prompt('请输入姓名',{placeholder:'请输入...'}); if(v) MeToast.info('你好,'+v+''); } async function demoPrompt() { const v=await MeToast.prompt('请输入姓名',{placeholder:'请输入...'}); if(v) MeToast.info('你好,'+v+''); }
async function demoPromptPassword() { const v=await MeToast.prompt('请输入密码',{placeholder:'密码',inputType:'password',submitText:'登录'}); if(v) MeToast.info('密码已输入'); }
// 进度 & 队列 // === Progress & Countdown ===
function demoProgress() { const p=MeToast.progress('上传中...'); let v=0; const t=setInterval(()=>{v+=Math.random()*28; if(v>=100){clearInterval(t);p.complete('完成!');}else p.setProgress(v);},400); } function demoProgress() { const p=MeToast.progress('上传中...',{progressColor:'#3b82f6'}); let v=0; const t=setInterval(()=>{v+=Math.random()*25; if(v>=100){clearInterval(t);p.complete('上传完成!');}else p.setProgress(v);},400); }
function demoProgressV() { const p=MeToast.progress('上传中...',{progressColor:'#10b981',progressDirection:'vertical'}); let v=0; const t=setInterval(()=>{v+=Math.random()*25; if(v>=100){clearInterval(t);p.complete('完成!');}else p.setProgress(v);},400); }
function demoCountdown() { MeToast.countdown('{seconds} 秒后执行',5,{onComplete:()=>MeToast.success('已执行')}); } function demoCountdown() { MeToast.countdown('{seconds} 秒后执行',5,{onComplete:()=>MeToast.success('已执行')}); }
async function demoQueue() { await MeToast.queue(['步骤一','步骤二','步骤三'],{delay:800,duration:2000,type:'info'}); } function demoCountdownPause() {
function demoStack() { MeToast.stack(['消息1','消息2','消息3','消息4'],{stagger:150,type:'info'}); } const c=MeToast.countdown('{seconds}s 可暂停',10,{type:'info',onComplete:()=>MeToast.success('倒计时结束')});
setTimeout(()=>{c.pause();MeToast.warning('已暂停3秒后恢复',{duration:3000})},4000);
// Action setTimeout(()=>{c.resume();MeToast.info('已恢复倒计时')},7000);
function demoActionDelete() {
let deleted=true;
MeToast.action('文件 data.json 已删除',[{text:'撤销',onClick:()=>{deleted=false;MeToast.success('已撤销删除');},color:'#3b82f6'}]);
}
function demoActionMulti() {
MeToast.action('邮件已发送',[
{text:'查看',onClick:()=>MeToast.info('打开邮件详情'),color:'#3b82f6'},
{text:'撤回',onClick:()=>MeToast.warning('邮件已撤回'),color:'#f59e0b'},
]);
}
function demoActionSuccess() {
MeToast.action('上传完成',[{text:'查看文件',onClick:()=>MeToast.info('打开文件管理器'),color:'#10b981'}]);
} }
// 分组 // === Queue & Stack ===
async function demoQueue() { await MeToast.queue(['第一步','第二步','第三步'],{delay:800,duration:2000,type:'info'}); }
async function demoQueueCancel() {
const q=MeToast.queue(['步骤1','步骤2','步骤3','步骤4','步骤5'],{delay:600,duration:1500,type:'info'});
setTimeout(()=>{q.cancel();MeToast.warning('队列已取消',{duration:2000});},3500);
}
function demoStack() { MeToast.stack(['消息1','消息2','消息3','消息4','消息5'],{stagger:120,type:'info'}); }
function demoStackMixed() {
MeToast.stack(['普通消息',{message:'警告消息',type:'warning',duration:5000},{message:'错误消息',type:'error'}],{stagger:150});
}
// === Action ===
function demoActionDelete() { MeToast.action('文件 data.json 已删除',[{text:'撤销',onClick:()=>MeToast.success('已撤销'),color:'#3b82f6'}]); }
function demoActionMulti() { MeToast.action('邮件已发送',[{text:'查看',onClick:()=>MeToast.info('打开邮件详情'),color:'#3b82f6'},{text:'撤回',onClick:()=>MeToast.warning('已撤回'),color:'#f59e0b'}]); }
function demoActionNoClose() { MeToast.action('完成后点击关闭',[{text:'我知道了',onClick:()=>{},color:'#10b981'}]); }
// === Group ===
const group = MeToast.group('demo-group'); const group = MeToast.group('demo-group');
function demoGroup() { group.success('分组消息 #'+(group.count()+1)); group.info('分组消息 #'+(group.count()+1)); } function demoGroup() { group.success('分组成功 #'+group.count()); group.info('分组消息 #'+group.count()); }
function dismissGroup() { MeToast.dismissGroup('demo-group'); MeToast.info('已关闭 demo-group 分组'); } function dismissGroup() { MeToast.dismissGroup('demo-group'); MeToast.info('分组已关闭'); }
function demoGroupMixed() {
const g = MeToast.group('mixed-test');
g.success('OK'); g.warning('Warning'); g.info('Info');
setTimeout(()=>MeToast.dismissGroup('mixed-test'),4000);
}
// 动画 // === Animation ===
function anim(name) { MeToast.success('动画: '+name,{animation:name,duration:3000}); } function anim(name) { MeToast.success('动画: '+name,{animation:name,duration:3000,showProgress:false}); }
function switchTheme(t) { MeToast.themes.switchTheme(t); MeToast.configure({theme:t}); const n={light:'浅色',dark:'深色',auto:'自动',warm:'暖色'}; MeToast.info('主题: '+n[t],{theme:t}); }
// === Theme ===
function switchTheme(t) { MeToast.themes.switchTheme(t); MeToast.configure({theme:t}); MeToast.info('主题: '+t,{theme:t}); }
function demoRegisterTheme() {
try {
MeToast.themes.registerTheme('sunset',{bg:'rgba(255,248,240,0.96)',text:'#92400e',border:'rgba(249,115,22,0.2)',shadow:'0 10px 36px -10px rgba(249,115,22,0.2)',hoverShadow:'0 14px 48px -10px rgba(249,115,22,0.3)',progressBg:'rgba(249,115,22,0.1)',closeHoverBg:'rgba(249,115,22,0.1)'});
MeToast.themes.switchTheme('sunset');
MeToast.configure({theme:'sunset'});
MeToast.success('已切换到 sunset 主题',{theme:'sunset'});
} catch(_) { MeToast.warning('主题已注册,已切换'); }
}
// === Plugins ===
function demoCustomPlugin() {
MeToast.use({name:'click-counter',version:'1.0',install(){let c=0;Toast.on('afterShow',t=>{c++;setTimeout(()=>t.update({message:t.message.replace(/\\(\\d+\\)/,'')+' (总通知#'+c+')'}),1);});}});
MeToast.info('自定义插件已安装(消息后追加计数)');
}
// === v2.0 new features ===
function demoResetTimer() {
const t=MeToast.info('这条消息不会自动消失(resetTimer',{duration:3000,resetTimerOnUpdate:true,closeButton:true});
let n=0; const iv=setInterval(()=>{n++;if(n>8){clearInterval(iv);t.close();return;}t.update({message:'重置计时器 #'+n+' — 每次更新重置3秒'});},1000);
}
function demoOnUpdate() { const t=MeToast.success('onUpdate 演示',{onUpdate:t=>{console.log('更新了:',t.message);}}); setTimeout(()=>t.update({message:'已更新!'}),1000); setTimeout(()=>t.update({message:'再次更新!'}),2000); }
function demoCustomRender() {
MeToast.show({render:toast=>'<div style="background:#111;color:#0f0;padding:16px 20px;border-radius:10px;border:1px solid #0f0;font-family:monospace">🟢 <b>'+toast.message+'</b><br><span style="font-size:11px;opacity:0.6"># custom render by thzxx</span></div>',message:'自定义渲染内容',duration:5000});
}
function demoNotify() {
if(typeof Notification==='undefined'){MeToast.error('浏览器不支持 Notification');return;}
if(Notification.permission==='denied'){MeToast.error('通知权限已拒绝');return;}
MeToast.info('页面隐藏时看系统通知',{notifyWhenHidden:true,duration:6000});
}
// === Management ===
function demoFindById() {
const t=MeToast.info('这是测试 toast',{duration:5000});
setTimeout(()=>{const found=MeToast.find(t.id); if(found)MeToast.success('找到了 #'+found.id);},500);
}
function demoGetAll() { const all=MeToast.getAll(); MeToast.info('当前共 '+all.size+' 条 toast'); }
function demoClearByPos() { MeToast.error('右下角临时消息',{position:'bottom-right',duration:3000}); setTimeout(()=>{MeToast.clear('bottom-right');MeToast.info('右下角已清除');},500); }
function demoGetConfig() { try{const c=MeToast.getConfig();MeToast.info('配置: '+JSON.stringify({position:c.position,duration:c.duration,theme:c.theme,animation:c.animation,locale:c.locale}).replace(/"/g,''),{duration:5000});}catch(e){MeToast.error('无 getConfig 方法');} }
// === Interaction ===
function demoDraggable() { MeToast.info('← 试试拖动我来关闭',{draggable:true,duration:8000,closeButton:true}); }
function demoPauseHover() { MeToast.info('鼠标悬停在我上面,倒计时会暂停',{pauseOnHover:true,duration:8000}); }
function demoCloseOnClick() { MeToast.warning('点击我即可关闭',{closeOnClick:true,duration:10000}); }
function demoWidth() { MeToast.info('宽550px',{width:550}); setTimeout(()=>MeToast.info('宽280px(窄)',{width:280}),500); }
function demoClassName() { MeToast.success('带自定义 className',{className:'demo-custom-class'}); }
function demoCustomIcon() {
MeToast.info('通用通知', {
iconHTML: '<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/></svg>'
});
}
// === i18n ===
function switchLocale(loc) {
try{MeToast.i18n.switchLocale(loc);MeToast.configure({locale:loc});MeToast.success(loc==='zh-CN'?'已切换到中文':'Switched to English',{theme:'dark'});}
catch(e){MeToast.info('已切换语言');}
}
function demoFormat() {
try{
MeToast.info('数字: '+MeToast.i18n.formatNumber(1234567)+' | 货币: '+MeToast.i18n.formatCurrency(99.5,'CNY')+' | 日期: '+MeToast.i18n.formatDate(new Date()),{duration:8000});
}catch(e){MeToast.info('格式化: 1234567 → 1,234,567');}
}
// === 图标网格 ===
(function renderIcons() {
var grid = document.getElementById('icon-grid');
if (!grid) return;
var icons = ['success','error','warning','info','loading','close','check','x','alert','question','star','heart','bell','mail','settings','user','home','search','plus','minus','edit','trash','download','upload','share','link','external','clock','calendar','map','compass','globe','wifi','cloud','sun','moon','zap','activity','cpu','database','server','terminal','code','git','package','layers','grid','list','filter','sort','refresh','sync','power','battery','bluetooth','volume','mic','camera','image','video','music','file','folder','clipboard','save','print','eye','eyeOff','lock','unlock','shield','key','flag','bookmark','tag','gift','award','target','crosshair','move','maximize','minimize','copy','cut','paste','rotateCw','rotateCcw','zoomIn','zoomOut','crop','sliders','toggleLeft','toggleRight','checkCircle','xCircle','alertCircle','infoCircle','helpCircle','alertTriangle','checkSquare','square','circle','triangle','hexagon','octagon','pentagon','diamond'];
icons.forEach(function(ic) {
var btn = document.createElement('button');
btn.className = 'btn btn-outline btn-tiny';
btn.textContent = ic;
btn.title = 'type=' + ic;
btn.onclick = function() { MeToast.success(ic, { type: ic, duration: 2000, showProgress: false }); };
grid.appendChild(btn);
});
})();
</script> </script>
</body> </body>
</html> </html>
+278 -136
View File
@@ -3,6 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<title>API 文档 — MetonaToast</title> <title>API 文档 — MetonaToast</title>
<style> <style>
:root { :root {
@@ -23,22 +24,21 @@
.sidebar a:hover, .sidebar a.active { color:var(--accent2); border-left-color:var(--accent); background:rgba(99,102,241,0.06); } .sidebar a:hover, .sidebar a.active { color:var(--accent2); border-left-color:var(--accent); background:rgba(99,102,241,0.06); }
.sidebar .section { font-size:11px; text-transform:uppercase; letter-spacing:1px; padding:16px 24px 6px; color:var(--muted); font-weight:600; } .sidebar .section { font-size:11px; text-transform:uppercase; letter-spacing:1px; padding:16px 24px 6px; color:var(--muted); font-weight:600; }
.main { flex:1; padding:40px 48px; max-width:900px; } .main { flex:1; padding:40px 48px; max-width:950px; }
.main h1 { font-size:30px; font-weight:700; margin-bottom:8px; } .main h1 { font-size:30px; font-weight:700; margin-bottom:8px; }
.main h2 { font-size:22px; font-weight:700; margin:40px 0 12px; padding-top:20px; border-top:1px solid var(--border); } .main h2 { font-size:22px; font-weight:700; margin:44px 0 14px; padding-top:22px; border-top:1px solid var(--border); }
.main h3 { font-size:17px; font-weight:600; margin:24px 0 8px; color:var(--accent2); } .main h3 { font-size:17px; font-weight:600; margin:28px 0 10px; color:var(--accent2); }
.main p { margin:8px 0; color:var(--muted); font-size:14px; } .main p { margin:8px 0; color:var(--muted); font-size:14px; }
.main table { width:100%; border-collapse:collapse; margin:12px 0; font-size:13px; } .main table { width:100%; border-collapse:collapse; margin:14px 0 20px; font-size:13px; }
.main th, .main td { text-align:left; padding:8px 14px; border-bottom:1px solid var(--border); } .main th, .main td { text-align:left; padding:9px 14px; border-bottom:1px solid var(--border); vertical-align:top; }
.main th { color:var(--muted); font-weight:500; font-size:11px; text-transform:uppercase; letter-spacing:0.5px; } .main th { color:var(--muted); font-weight:500; font-size:11px; text-transform:uppercase; letter-spacing:0.5px; }
.main td:first-child { color:var(--accent2); font-family:monospace; font-size:12px; white-space:nowrap; } .main td:first-child { color:var(--accent2); font-family:monospace; font-size:12px; white-space:nowrap; }
.tag { display:inline-block; padding:2px 8px; border-radius:4px; font-size:11px; font-weight:600; } .main td:nth-child(3) { font-family:monospace; font-size:11px; color:var(--muted); }
.tag-method { background:rgba(59,130,246,0.15); color:#60a5fa; }
.tag-config { background:rgba(16,185,129,0.15); color:#34d399; }
.tag-callback { background:rgba(139,92,246,0.15); color:#a78bfa; }
.badge { display:inline-block; padding:1px 7px; border-radius:3px; font-size:10px; font-weight:700; margin-left:6px; vertical-align:middle; } .badge { display:inline-block; padding:1px 7px; border-radius:3px; font-size:10px; font-weight:700; margin-left:6px; vertical-align:middle; }
.badge-new { background:rgba(16,185,129,0.2); color:#34d399; } .badge-new { background:rgba(16,185,129,0.2); color:#34d399; }
.badge-v2 { background:rgba(99,102,241,0.2); color:#818cf8; } .hint { font-size:12px; color:var(--muted); margin-top:2px; }
.return-box { background:rgba(16,185,129,0.08); border:1px solid rgba(16,185,129,0.2); border-radius:8px; padding:14px 18px; margin:12px 0; }
.return-box h4 { font-size:12px; color:#34d399; margin-bottom:6px; text-transform:uppercase; letter-spacing:0.5px; }
@media (max-width:768px) { @media (max-width:768px) {
body { flex-direction:column; } body { flex-direction:column; }
@@ -73,6 +73,7 @@
<div class="section">管理方法</div> <div class="section">管理方法</div>
<a href="#group">group() <span class="badge badge-new">NEW</span></a> <a href="#group">group() <span class="badge badge-new">NEW</span></a>
<a href="#dismiss">dismiss()</a> <a href="#dismiss">dismiss()</a>
<a href="#clear">clear()</a>
<a href="#configure">configure()</a> <a href="#configure">configure()</a>
<a href="#use">use()</a> <a href="#use">use()</a>
<a href="#destroy">destroy()</a> <a href="#destroy">destroy()</a>
@@ -86,159 +87,303 @@
<main class="main"> <main class="main">
<h1>API 文档</h1> <h1>API 文档</h1>
<p>MetonaToast v2.0.0 完整 API 参考。所有方法均支持链式调用和配置覆盖</p> <p>MetonaToast v2.0.0 完整 API 参考。所有基础通知方法(show/success/error/warning/info/loading)支持两种调用形式,均可传入任何 <a href="#config">配置项</a> 作为可选第二参数</p>
<!-- ===== 基础通知 ===== --> <!-- ===== 基础通知 ===== -->
<h2 id="show">show(message, opts?)</h2> <h2 id="show">show(message, opts?)</h2>
<p>显示默认类型的 Toast 通知。</p> <p>显示默认类型的 Toast 通知,无特定颜色和图标</p>
<pre><span class="cm">// 字符串</span> <table>
<tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
<tr><td>message</td><td>string | object</td><td></td><td>消息字符串,或包含 title/message 等属性的配置对象</td></tr>
<tr><td>opts</td><td>object</td><td>{}</td><td>可选配置对象,覆盖 <a href="#config">全部配置项</a>。仅当 message 为字符串时有效</td></tr>
</table>
<pre><span class="cm">// 字符串形式</span>
MeToast.<span class="fn">show</span>(<span class="s">'默认消息'</span>); MeToast.<span class="fn">show</span>(<span class="s">'默认消息'</span>);
<span class="cm">// 带配置</span>
MeToast.<span class="fn">show</span>(<span class="s">'自定义'</span>, { <span class="fn">duration</span>: 2000, <span class="fn">position</span>: <span class="s">'bottom-center'</span> }); MeToast.<span class="fn">show</span>(<span class="s">'自定义'</span>, { <span class="fn">duration</span>: 2000, <span class="fn">position</span>: <span class="s">'bottom-center'</span> });
<span class="cm">// 对象形式(所有 opts 作为一级属性)</span>
<span class="cm">// 对象形式</span> MeToast.<span class="fn">show</span>({ <span class="fn">title</span>: <span class="s">'标题'</span>, <span class="fn">message</span>: <span class="s">'内容'</span>, <span class="fn">duration</span>: 3000 });</pre>
MeToast.<span class="fn">show</span>({ <span class="fn">title</span>: <span class="s">'标题'</span>, <span class="fn">message</span>: <span class="s">'内容'</span> });</pre>
<h2 id="success">success(message, opts?)</h2> <h2 id="success">success(message, opts?)</h2>
<p>显示成功通知。绿色对勾图标。</p> <p>显示成功通知。绿色对勾图标 <code>#10b981</code>type = success</p>
<table>
<tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
<tr><td>message</td><td>string | object</td><td></td><td>消息字符串或配置对象</td></tr>
<tr><td>opts</td><td>object</td><td>{}</td><td>可选配置覆盖。type 固定为 success</td></tr>
</table>
<pre>MeToast.<span class="fn">success</span>(<span class="s">'保存成功!'</span>); <pre>MeToast.<span class="fn">success</span>(<span class="s">'保存成功!'</span>);
MeToast.<span class="fn">success</span>({ <span class="fn">title</span>: <span class="s">'已保存'</span>, <span class="fn">message</span>: <span class="s">'文件已同步到云端'</span> });</pre> MeToast.<span class="fn">success</span>({ <span class="fn">title</span>: <span class="s">'已保存'</span>, <span class="fn">message</span>: <span class="s">'数据已同步'</span> });
Met.<span class="fn">success</span>(<span class="s">'MeToast和Met等价'</span>);</pre>
<h2 id="error">error(message, opts?)</h2> <h2 id="error">error(message, opts?)</h2>
<p>显示错误通知。红色叉号图标。</p> <p>显示错误通知。红色叉号图标 <code>#ef4444</code>type = error。aria-live 设为 assertive</p>
<pre>MeToast.<span class="fn">error</span>(<span class="s">'网络错误,请重试'</span>);</pre> <table>
<tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
<tr><td>message</td><td>string | object</td><td></td><td>消息字符串或配置对象</td></tr>
<tr><td>opts</td><td>object</td><td>{}</td><td>可选配置覆盖。type 固定为 error</td></tr>
</table>
<pre>MeToast.<span class="fn">error</span>(<span class="s">'网络错误,请重试'</span>);
MeToast.<span class="fn">error</span>({ <span class="fn">title</span>: <span class="s">'提交失败'</span>, <span class="fn">message</span>: <span class="s">'服务器不可达'</span> });</pre>
<h2 id="warning">warning(message, opts?)</h2> <h2 id="warning">warning(message, opts?)</h2>
<p>显示警告通知。黄色三角图标。</p> <p>显示警告通知。黄色三角图标 <code>#f59e0b</code>type = warning</p>
<table>
<tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
<tr><td>message</td><td>string | object</td><td></td><td>消息字符串或配置对象</td></tr>
<tr><td>opts</td><td>object</td><td>{}</td><td>可选配置覆盖。type 固定为 warning</td></tr>
</table>
<pre>MeToast.<span class="fn">warning</span>(<span class="s">'请注意检查输入内容'</span>);</pre> <pre>MeToast.<span class="fn">warning</span>(<span class="s">'请注意检查输入内容'</span>);</pre>
<h2 id="info">info(message, opts?)</h2> <h2 id="info">info(message, opts?)</h2>
<p>显示信息通知。蓝色圆形图标。</p> <p>显示信息通知。蓝色圆形图标 <code>#3b82f6</code>type = info</p>
<pre>MeToast.<span class="fn">info</span>(<span class="s">'系统将于 22:00 进行维护'</span>);</pre> <table>
<tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
<tr><td>message</td><td>string | object</td><td></td><td>消息字符串或配置对象</td></tr>
<tr><td>opts</td><td>object</td><td>{}</td><td>可选配置覆盖。type 固定为 info</td></tr>
</table>
<pre>MeToast.<span class="fn">info</span>(<span class="s">'系统将于 22:00 维护'</span>);</pre>
<h2 id="loading">loading(message, opts?)</h2> <h2 id="loading">loading(message, opts?)</h2>
<p>显示加载状态。返回一个控制对象,支持链式转换为 success/error/info/warning</p> <p>显示加载状态。type = loadingduration 强制为 0(不自动关闭),closeButton 和 showProgress 强制为 false。返回 LoadingControl 对象</p>
<table>
<tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
<tr><td>message</td><td>string | object</td><td></td><td>加载提示文本或配置对象</td></tr>
<tr><td>opts</td><td>object</td><td>{}</td><td>可选配置覆盖</td></tr>
</table>
<pre><span class="kw">const</span> loading = MeToast.<span class="fn">loading</span>(<span class="s">'正在提交...'</span>); <pre><span class="kw">const</span> loading = MeToast.<span class="fn">loading</span>(<span class="s">'正在提交...'</span>);
<span class="fn">setTimeout</span>(() => loading.<span class="fn">success</span>(<span class="s">'提交成功!'</span>), 2000); <span class="fn">setTimeout</span>(() => loading.<span class="fn">success</span>(<span class="s">'提交成功!'</span>), 2000);</pre>
<div class="return-box">
<span class="cm">// 返回对象方法</span> <h4>返回 LoadingControl</h4>
loading.<span class="fn">success</span>(msg, opts?) <span class="cm">// 转为成功</span> <table>
loading.<span class="fn">error</span>(msg, opts?) <span class="cm">// 转为错误</span> <tr><th>方法</th><th>签名</th><th>说明</th></tr>
loading.<span class="fn">info</span>(msg, opts?) <span class="cm">// 转为信息</span> <tr><td>success</td><td>(msg, opts?) => ToastInstance</td><td>关闭加载 toast,原地替换为 success 类型</td></tr>
loading.<span class="fn">warning</span>(msg, opts?) <span class="cm">// 转为警告</span> <tr><td>error</td><td>(msg, opts?) => ToastInstance</td><td>替换为 error 类型</td></tr>
loading.<span class="fn">update</span>(partial) <span class="cm">// 原地更新</span> <tr><td>info</td><td>(msg, opts?) => ToastInstance</td><td>替换为 info 类型</td></tr>
loading.<span class="fn">dismiss</span>() <span class="cm">// 关闭</span></pre> <tr><td>warning</td><td>(msg, opts?) => ToastInstance</td><td>替换为 warning 类型</td></tr>
<tr><td>update</td><td>(partial) => MeToast</td><td>不关闭加载 toast,原地更新其内容(支持 resetTimerOnUpdate</td></tr>
<tr><td>dismiss</td><td>()</td><td>直接关闭加载 toast 不替换</td></tr>
</table>
</div>
<!-- ===== 高级功能 ===== --> <!-- ===== 高级功能 ===== -->
<h2 id="promise">promise(promise, opts)</h2> <h2 id="promise">promise(promise, opts)</h2>
<p>自动根据 Promise 状态切换 Toast。显示 loading → 自动 success/error</p> <p>监听 Promise 生命周期。自动显示 loading → 根据 resolve/reject 自动切换 success/error。返回原 Promise,支持 await 获取结果</p>
<pre><span class="kw">await</span> MeToast.<span class="fn">promise</span>( <table>
<span class="fn">fetch</span>(<span class="s">'/api/data'</span>), <tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
{ <tr><td>promise</td><td>Promise</td><td></td><td>要监听的 Promise 对象。非 Promise 会打印错误并返回 rejected Promise</td></tr>
<tr><td>opts.loading</td><td>string</td><td>"加载中..."</td><td>加载中显示的文本</td></tr>
<tr><td>opts.success</td><td>string</td><td>"操作成功"</td><td>resolve 后显示的文本</td></tr>
<tr><td>opts.error</td><td>string</td><td>"操作失败"</td><td>reject 后显示的文本</td></tr>
</table>
<pre><span class="kw">try</span> {
<span class="kw">await</span> MeToast.<span class="fn">promise</span>(<span class="fn">fetch</span>(<span class="s">'/api/data'</span>), {
<span class="fn">loading</span>: <span class="s">'加载中...'</span>, <span class="fn">loading</span>: <span class="s">'加载中...'</span>,
<span class="fn">success</span>: <span class="s">'加载完成!'</span>, <span class="fn">success</span>: <span class="s">'加载完成!'</span>,
<span class="fn">error</span>: <span class="s">'加载失败'</span>, <span class="fn">error</span>: <span class="s">'加载失败'</span>,
} });
);</pre> } <span class="kw">catch</span> (<span class="fn">e</span>) { <span class="cm">/* promise reject 会继续抛出 */</span> }</pre>
<table>
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
<tr><td>promise</td><td>Promise</td><td>要监听的 Promise 对象</td></tr>
<tr><td>opts.loading</td><td>string</td><td>加载中文本</td></tr>
<tr><td>opts.success</td><td>string</td><td>成功时文本</td></tr>
<tr><td>opts.error</td><td>string</td><td>失败时文本</td></tr>
</table>
<h2 id="confirm">confirm(message, opts?)</h2> <h2 id="confirm">confirm(message, opts?)</h2>
<p>确认对话框。返回 <code>Promise&lt;boolean&gt;</code>,用户点击确认返回 true</p> <p>确认对话框。返回 <code>Promise&lt;boolean&gt;</code>。内置 10 秒安全超时,超时自动 resolve(false)</p>
<pre><span class="kw">const</span> ok = <span class="kw">await</span> MeToast.<span class="fn">confirm</span>(<span class="s">'确定删除吗?'</span>, { <table>
<tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
<tr><td>message</td><td>string</td><td></td><td>对话框消息。非字符串会打印错误并 resolve(false)</td></tr>
<tr><td>opts.confirmText</td><td>string</td><td>"确认"</td><td>确认按钮文字</td></tr>
<tr><td>opts.confirmColor</td><td>string</td><td>"#10b981"</td><td>确认按钮背景色</td></tr>
<tr><td>opts.cancelText</td><td>string</td><td>"取消"</td><td>取消按钮文字</td></tr>
<tr><td>opts.cancelColor</td><td>string</td><td>"#6b7280"</td><td>取消按钮背景色</td></tr>
<tr><td>opts.type</td><td>string</td><td>"warning"</td><td>Toast 类型(影响图标和颜色)</td></tr>
</table>
<pre><span class="kw">const</span> ok = <span class="kw">await</span> MeToast.<span class="fn">confirm</span>(<span class="s">'确定删除?'</span>, {
<span class="fn">confirmText</span>: <span class="s">'删除'</span>, <span class="fn">confirmText</span>: <span class="s">'删除'</span>,
<span class="fn">confirmColor</span>: <span class="s">'#ef4444'</span>, <span class="fn">confirmColor</span>: <span class="s">'#ef4444'</span>,
<span class="fn">cancelText</span>: <span class="s">'取消'</span>, <span class="fn">cancelText</span>: <span class="s">'保留'</span>,
}); });
<span class="kw">if</span> (ok) MeToast.<span class="fn">success</span>(<span class="s">'已删除'</span>);</pre> <span class="kw">if</span> (ok) MeToast.<span class="fn">success</span>(<span class="s">'已删除'</span>);</pre>
<h2 id="prompt">prompt(message, opts?)</h2> <h2 id="prompt">prompt(message, opts?)</h2>
<p>输入对话框。返回 <code>Promise&lt;string|null&gt;</code>,用户取消返回 null</p> <p>输入对话框。返回 <code>Promise&lt;string|null&gt;</code>。按 Enter 或点击提交按钮返回输入值,取消返回 null。内置 10 秒安全超时</p>
<table>
<tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
<tr><td>message</td><td>string</td><td></td><td>对话框消息。非字符串会打印错误并 resolve(null)</td></tr>
<tr><td>opts.placeholder</td><td>string</td><td>""</td><td>输入框占位文字</td></tr>
<tr><td>opts.defaultValue</td><td>string</td><td>""</td><td>输入框默认值</td></tr>
<tr><td>opts.inputType</td><td>string</td><td>"text"</td><td>input 标签 type 属性(如 password/email/number</td></tr>
<tr><td>opts.submitText</td><td>string</td><td>"确认"</td><td>提交按钮文字</td></tr>
<tr><td>opts.submitColor</td><td>string</td><td>"#3b82f6"</td><td>提交按钮背景色</td></tr>
<tr><td>opts.cancelText</td><td>string</td><td>"取消"</td><td>取消按钮文字</td></tr>
<tr><td>opts.cancelColor</td><td>string</td><td>"#6b7280"</td><td>取消按钮背景色</td></tr>
<tr><td>opts.type</td><td>string</td><td>"info"</td><td>Toast 类型</td></tr>
</table>
<pre><span class="kw">const</span> name = <span class="kw">await</span> MeToast.<span class="fn">prompt</span>(<span class="s">'请输入姓名'</span>, { <pre><span class="kw">const</span> name = <span class="kw">await</span> MeToast.<span class="fn">prompt</span>(<span class="s">'请输入姓名'</span>, {
<span class="fn">placeholder</span>: <span class="s">'请输入...'</span>, <span class="fn">placeholder</span>: <span class="s">'请输入...'</span>,
<span class="fn">defaultValue</span>: <span class="s">'张三'</span>, <span class="fn">defaultValue</span>: <span class="s">'张三'</span>,
<span class="fn">submitText</span>: <span class="s">'确定'</span>,
}); });
<span class="kw">if</span> (name) MeToast.<span class="fn">info</span>(<span class="s">'你好,'</span> + name + <span class="s">''</span>);</pre> <span class="kw">if</span> (name) MeToast.<span class="fn">info</span>(<span class="s">'你好,'</span> + name);</pre>
<h2 id="progress">progress(message, opts?)</h2> <h2 id="progress">progress(message, opts?)</h2>
<p>进度条通知。返回控制对象,可调用 setProgress / complete / error</p> <p>进度条通知。不自动关闭。返回 ProgressControl 对象以手动更新进度</p>
<pre><span class="kw">const</span> p = MeToast.<span class="fn">progress</span>(<span class="s">'上传中...'</span>); <table>
p.<span class="fn">setProgress</span>(30); <tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
p.<span class="fn">setProgress</span>(70); <tr><td>message</td><td>string | object</td><td></td><td>进度提示文本或配置对象</td></tr>
p.<span class="fn">complete</span>(<span class="s">'上传完成!'</span>); <tr><td>opts</td><td>object</td><td>{}</td><td>可选配置。type 默认 info</td></tr>
<tr><td>opts.progressColor</td><td>string</td><td>"#3b82f6"</td><td>进度条填充颜色</td></tr>
</table>
<pre><span class="kw">const</span> p = MeToast.<span class="fn">progress</span>(<span class="s">'上传中...'</span>, { <span class="fn">progressColor</span>: <span class="s">'#10b981'</span> });
p.<span class="fn">setProgress</span>(45); <span class="cm">// → 45%</span>
p.<span class="fn">setProgress</span>(90); <span class="cm">// → 90%</span>
p.<span class="fn">complete</span>(<span class="s">'上传完成!'</span>); <span class="cm">// → 100% → success</span>
<span class="cm">// 或</span> <span class="cm">// 或</span>
p.<span class="fn">error</span>(<span class="s">'上传失败'</span>); p.<span class="fn">error</span>(<span class="s">'上传失败'</span>);
p.<span class="fn">dismiss</span>();</pre> p.<span class="fn">dismiss</span>();</pre>
<div class="return-box">
<h4>返回 ProgressControl</h4>
<table>
<tr><th>方法</th><th>签名</th><th>说明</th></tr>
<tr><td>setProgress</td><td>(percent: number)</td><td>设置进度 0~100,自动 clamp。更新进度条宽度和百分比文字</td></tr>
<tr><td>complete</td><td>(message?: string)</td><td>跳到 100%300ms 后替换为 success toast1s 后自动关闭</td></tr>
<tr><td>error</td><td>(message?: string)</td><td>替换为 error toast2s 后自动关闭</td></tr>
<tr><td>dismiss</td><td>()</td><td>直接关闭</td></tr>
</table>
</div>
<h2 id="countdown">countdown(message, seconds, opts?)</h2> <h2 id="countdown">countdown(message, seconds, opts?)</h2>
<p>倒计时 Toast。<code>{seconds}</code> 占位符自动替换为剩余秒数。</p> <p>倒计时 Toast。<code>{seconds}</code> 占位符每秒自动替换为剩余秒数。</p>
<pre>MeToast.<span class="fn">countdown</span>(<span class="s">'操作将在 {seconds} 秒后执行'</span>, 5, { <table>
<tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
<tr><td>message</td><td>string</td><td></td><td>消息文本。支持 <code>{seconds}</code> 占位符。非字符串打印错误并返回空控制对象</td></tr>
<tr><td>seconds</td><td>number</td><td>10</td><td>倒计时秒数,最小 1</td></tr>
<tr><td>opts.onComplete</td><td>function</td><td></td><td>倒计时归零时的回调</td></tr>
<tr><td>opts.type</td><td>string</td><td>"warning"</td><td>Toast 类型</td></tr>
</table>
<pre>MeToast.<span class="fn">countdown</span>(<span class="s">'{seconds} 秒后执行'</span>, 5, {
<span class="fn">onComplete</span>: () => MeToast.<span class="fn">success</span>(<span class="s">'已执行'</span>), <span class="fn">onComplete</span>: () => MeToast.<span class="fn">success</span>(<span class="s">'已执行'</span>),
}); });</pre>
<div class="return-box">
<span class="cm">// 返回控制对象</span> <h4>返回 CountdownControl</h4>
<span class="kw">const</span> c = MeToast.<span class="fn">countdown</span>(<span class="s">'{seconds}s'</span>, 10); <table>
c.<span class="fn">cancel</span>(); <span class="cm">// 取消并关闭</span> <tr><th>方法</th><th>说明</th></tr>
c.<span class="fn">pause</span>(); <span class="cm">// 暂停</span> <tr><td>cancel()</td><td>清除计时器并关闭 toast</td></tr>
c.<span class="fn">resume</span>(); <span class="cm">// 恢复</span></pre> <tr><td>pause()</td><td>暂停倒计时</td></tr>
<tr><td>resume()</td><td>恢复倒计时</td></tr>
</table>
</div>
<h2 id="queue">queue(messages, opts?)</h2> <h2 id="queue">queue(messages, opts?)</h2>
<p>队列展示:顺序逐个显示消息。返回可取消的 thenable 对象</p> <p>顺序逐个显示消息队列。前一条关闭后延时显示下一条。返回 QueueControlthenable + cancel</p>
<pre><span class="kw">const</span> q = MeToast.<span class="fn">queue</span>([<span class="s">'步骤一'</span>, <span class="s">'步骤二'</span>, <span class="s">'步骤三'</span>], { <table>
<span class="fn">delay</span>: 800, <tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
<span class="fn">duration</span>: 2000, <tr><td>messages</td><td>Array&lt;string|object&gt;</td><td></td><td>消息数组。可为字符串或带 message/type/duration/onClose 的对象。非数组打印错误并返回空控制对象</td></tr>
<span class="fn">type</span>: <span class="s">'info'</span>, <tr><td>opts.delay</td><td>number</td><td>1000</td><td>每条消息关闭后到显示下一条的间隔(ms)</td></tr>
}); <tr><td>opts.duration</td><td>number</td><td>3000</td><td>每条消息显示时长(ms),可被消息级 duration 覆盖</td></tr>
q.<span class="fn">cancel</span>(); <span class="cm">// 取消队列</span> <tr><td>opts.onClose</td><td>function</td><td></td><td>全部队列完成后的回调。消息级 onClose 和队列级 onClose 都会依次调用</td></tr>
<span class="kw">await</span> q; <span class="cm">// 等待队列完成</span></pre> <tr><td>opts.type</td><td>string</td><td></td><td>默认类型</td></tr>
</table>
<pre><span class="kw">const</span> q = MeToast.<span class="fn">queue</span>([
<span class="s">'步骤一'</span>,
{ <span class="fn">message</span>: <span class="s">'步骤二'</span>, <span class="fn">duration</span>: 5000, <span class="fn">type</span>: <span class="s">'warning'</span> },
<span class="s">'步骤三'</span>,
], { <span class="fn">delay</span>: 800, <span class="fn">duration</span>: 2000, <span class="fn">type</span>: <span class="s">'info'</span> });
q.<span class="fn">cancel</span>(); <span class="cm">// 中途取消</span>
<span class="kw">await</span> q; <span class="cm">// 等待完成(thenable 支持 await</span></pre>
<div class="return-box">
<h4>返回 QueueControl (thenable)</h4>
<table>
<tr><th>方法</th><th>说明</th></tr>
<tr><td>.then(fn, rj)</td><td>Promise.then 代理,支持 await</td></tr>
<tr><td>.catch(rj)</td><td>Promise.catch 代理</td></tr>
<tr><td>.cancel()</td><td>设置取消标志,不再显示下一条消息</td></tr>
</table>
</div>
<h2 id="stack">stack(messages, opts?)</h2> <h2 id="stack">stack(messages, opts?)</h2>
<p>堆叠展示:同时错峰显示多条消息。</p> <p>同时错峰显示多条消息。每条间隔 stagger 毫秒依次出现,全部叠加在屏幕上。</p>
<pre>MeToast.<span class="fn">stack</span>([<span class="s">'消息1'</span>, <span class="s">'消息2'</span>, <span class="s">'消息3'</span>, <span class="s">'消息4'</span>], { <table>
<tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
<tr><td>messages</td><td>Array&lt;string|object&gt;</td><td></td><td>消息数组。可为字符串或带 message/type/duration 的对象。非数组打印错误</td></tr>
<tr><td>opts.stagger</td><td>number</td><td>100</td><td>每条消息之间的显示间隔(ms)</td></tr>
<tr><td>opts.type</td><td>string</td><td></td><td>默认类型</td></tr>
</table>
<pre>MeToast.<span class="fn">stack</span>([<span class="s">'消息1'</span>, <span class="s">'消息2'</span>, { <span class="fn">message</span>: <span class="s">'警告'</span>, <span class="fn">type</span>: <span class="s">'warning'</span> }], {
<span class="fn">stagger</span>: 150, <span class="fn">stagger</span>: 150,
<span class="fn">type</span>: <span class="s">'info'</span>, <span class="fn">type</span>: <span class="s">'info'</span>,
});</pre> });</pre>
<h2 id="action">action(message, actions, opts?) <span class="badge badge-new">v2.0</span></h2> <h2 id="action">action(message, actions, opts?) <span class="badge badge-new">v2.0</span></h2>
<p>Action Toast:内嵌操作按钮的通知。类似 Android Snackbar</p> <p>Action Toast:内嵌操作按钮。默认 duration=0 不自动关闭,closeButton=true</p>
<table>
<tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
<tr><td>message</td><td>string | object</td><td></td><td>消息字符串或配置对象</td></tr>
<tr><td>actions</td><td>ActionButton[]</td><td>[]</td><td>按钮数组。每个按钮可配 text/onClick/color/style/close</td></tr>
<tr><td>opts</td><td>object</td><td>{}</td><td>可选配置。duration 默认 0closeButton 默认 true</td></tr>
</table>
<table>
<tr><th>ActionButton 字段</th><th>类型</th><th>默认值</th><th>说明</th></tr>
<tr><td>text</td><td>string</td><td>—(必填)</td><td>按钮显示文字</td></tr>
<tr><td>onClick</td><td>(toast) => void</td><td>—(必填)</td><td>点击回调函数,参数为当前 toast 实例</td></tr>
<tr><td>color</td><td>string</td><td>"#6366f1"</td><td>按钮背景色</td></tr>
<tr><td>style</td><td>object</td><td>{}</td><td>按钮内联样式,可覆盖 colorstyle.background 优先)</td></tr>
<tr><td>close</td><td>boolean</td><td>true</td><td>点击后是否自动关闭 toast。设为 false 可多次点击</td></tr>
</table>
<pre>MeToast.<span class="fn">action</span>(<span class="s">'文件已删除'</span>, [ <pre>MeToast.<span class="fn">action</span>(<span class="s">'文件已删除'</span>, [
{ <span class="fn">text</span>: <span class="s">'撤销'</span>, <span class="fn">onClick</span>: () => <span class="fn">restore</span>(), <span class="fn">color</span>: <span class="s">'#3b82f6'</span> }, { <span class="fn">text</span>: <span class="s">'撤销'</span>, <span class="fn">onClick</span>: () => <span class="fn">restore</span>(), <span class="fn">color</span>: <span class="s">'#3b82f6'</span> },
{ <span class="fn">text</span>: <span class="s">'查看'</span>, <span class="fn">onClick</span>: () => <span class="fn">openFile</span>() }, { <span class="fn">text</span>: <span class="s">'查看详情'</span>, <span class="fn">onClick</span>: (t) => <span class="fn">openFile</span>(), <span class="fn">color</span>: <span class="s">'#10b981'</span>, <span class="fn">close</span>: false },
]);</pre> ]);</pre>
<table>
<tr><th>按钮字段</th><th>类型</th><th>说明</th></tr>
<tr><td>text</td><td>string</td><td>按钮文本</td></tr>
<tr><td>onClick</td><td>function</td><td>点击回调,参数为 toast 实例</td></tr>
<tr><td>color</td><td>string</td><td>按钮背景色,默认 #6366f1</td></tr>
<tr><td>close</td><td>boolean</td><td>点击后是否关闭 toast,默认 true</td></tr>
</table>
<!-- ===== 管理方法 ===== --> <!-- ===== 管理方法 ===== -->
<h2 id="group">group(name) <span class="badge badge-new">v2.0</span></h2> <h2 id="group">group(name) <span class="badge badge-new">v2.0</span></h2>
<p>创建 Toast 分组返回一个自动添加 <code>group</code> 参数的子对象,支持按组管理。</p> <p>创建 Toast 分组返回 GroupAPI 对象。该对象所有方法自动传入 <code>group: name</code>按组管理。</p>
<table>
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
<tr><td>name</td><td>string</td><td>分组名称。GroupAPI 和 dismissGroup 通过此名称关联</td></tr>
</table>
<pre><span class="kw">const</span> orders = MeToast.<span class="fn">group</span>(<span class="s">'orders'</span>); <pre><span class="kw">const</span> orders = MeToast.<span class="fn">group</span>(<span class="s">'orders'</span>);
orders.<span class="fn">success</span>(<span class="s">'订单已创建'</span>); orders.<span class="fn">success</span>(<span class="s">'订单已创建'</span>);
orders.<span class="fn">error</span>(<span class="s">'支付失败'</span>); orders.<span class="fn">error</span>(<span class="s">'支付失败'</span>, { <span class="fn">duration</span>: 5000 });
orders.<span class="fn">count</span>(); <span class="cm">// 该组 toast 数量</span> orders.<span class="fn">count</span>(); <span class="cm">// 该组当前 toast 数量</span>
orders.<span class="fn">dismiss</span>(); <span class="cm">// 关闭整组</span> orders.<span class="fn">dismiss</span>(); <span class="cm">// 关闭该组全部 toast</span>
<span class="cm">// 也支持主对象关闭</span>
<span class="cm">// 也可通过主对象关闭</span>
MeToast.<span class="fn">dismissGroup</span>(<span class="s">'orders'</span>);</pre> MeToast.<span class="fn">dismissGroup</span>(<span class="s">'orders'</span>);</pre>
<div class="return-box">
<h4>返回 GroupAPI</h4>
<table>
<tr><th>方法</th><th>说明</th></tr>
<tr><td>show(msg, opts?)</td><td>等价 MeToast.show,自动注入 group</td></tr>
<tr><td>success(msg, opts?)</td><td>等价 MeToast.success</td></tr>
<tr><td>error(msg, opts?)</td><td>等价 MeToast.error</td></tr>
<tr><td>warning(msg, opts?)</td><td>等价 MeToast.warning</td></tr>
<tr><td>info(msg, opts?)</td><td>等价 MeToast.info</td></tr>
<tr><td>loading(msg, opts?)</td><td>等价 MeToast.loading</td></tr>
<tr><td>action(msg, actions, opts?)</td><td>等价 MeToast.action</td></tr>
<tr><td>dismiss()</td><td>关闭该组所有 toast</td></tr>
<tr><td>count()</td><td>返回该组当前 toast 数量</td></tr>
</table>
</div>
<h2 id="dismiss">dismiss(id?)</h2> <h2 id="dismiss">dismiss(id?)</h2>
<p>关闭 Toast。无参数关闭所有,传 id 关闭指定</p> <p>关闭 Toast。无参数关闭全部</p>
<table>
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
<tr><td>id</td><td>string</td><td>可选。Toast 的 id,不传则关闭所有</td></tr>
</table>
<pre>MeToast.<span class="fn">dismiss</span>(); <span class="cm">// 关闭所有</span> <pre>MeToast.<span class="fn">dismiss</span>(); <span class="cm">// 关闭所有</span>
MeToast.<span class="fn">dismiss</span>(toastId); <span class="cm">// 关闭指定</span></pre> MeToast.<span class="fn">dismiss</span>(toast.id); <span class="cm">// 关闭指定</span></pre>
<p>其他管理方法:<code>count()</code> <code>getToasts()</code> <code>pauseAll()</code> <code>resumeAll()</code> <code>destroy()</code> <code>clear()</code></p>
<h2 id="clear">clear(position?)</h2>
<p>按位置清除 Toast。不传参数清除所有位置。</p>
<table>
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
<tr><td>position</td><td>string</td><td>可选。位置如 'top-right',不传则清除全部</td></tr>
</table>
<pre>MeToast.<span class="fn">clear</span>(); <span class="cm">// 全部</span>
MeToast.<span class="fn">clear</span>(<span class="s">'bottom-right'</span>); <span class="cm">// 仅右下角</span></pre>
<h2 id="configure">configure(opts)</h2> <h2 id="configure">configure(opts)</h2>
<p>全局配置影响后续所有 Toast。</p> <p>全局配置影响后续所有 Toast。theme 和 locale 变化会触发相应副作用(应用主题 CSS / 切换语言)。</p>
<table>
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
<tr><td>opts</td><td>object</td><td>包含任意 <a href="#config">配置项</a> 的对象</td></tr>
</table>
<pre>MeToast.<span class="fn">configure</span>({ <pre>MeToast.<span class="fn">configure</span>({
<span class="fn">position</span>: <span class="s">'top-right'</span>, <span class="fn">position</span>: <span class="s">'top-right'</span>,
<span class="fn">duration</span>: 4000, <span class="fn">duration</span>: 4000,
@@ -248,66 +393,64 @@ MeToast.<span class="fn">dismiss</span>(toastId); <span class="cm">// 关闭指
});</pre> });</pre>
<h2 id="use">use(plugin)</h2> <h2 id="use">use(plugin)</h2>
<p>安装插件。支持字符串(预设)和对象(自定义)</p> <p>安装插件。支持字符串(内置预设名)或插件对象。已被拒绝注册的无效插件会打印错误</p>
<table>
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
<tr><td>plugin</td><td>string | object</td><td>预设名 'keyboard'/'persistence'/'accessibility' 或自定义插件对象 { name, version?, install, uninstall? }</td></tr>
</table>
<pre>MeToast.<span class="fn">use</span>(<span class="s">'keyboard'</span>); <span class="cm">// ESC 关闭所有 Toast</span> <pre>MeToast.<span class="fn">use</span>(<span class="s">'keyboard'</span>); <span class="cm">// ESC 关闭所有 Toast</span>
MeToast.<span class="fn">use</span>(<span class="s">'persistence'</span>); <span class="cm">// 配置持久化到 localStorage</span> MeToast.<span class="fn">use</span>(<span class="s">'persistence'</span>); <span class="cm">// 配置自动保存到 localStorage</span>
MeToast.<span class="fn">use</span>(<span class="s">'accessibility'</span>); <span class="cm">// 屏幕阅读器朗读</span> MeToast.<span class="fn">use</span>(<span class="s">'accessibility'</span>); <span class="cm">// 屏幕阅读器实时朗读 toast 内容</span></pre>
<p class="hint">内置插件详情:keyboard 监听 keydown Escape 键;persistence 将配置写入 localStorage 并在页面加载时恢复;accessibility 在 afterShow/afterUpdate 钩子中通过 aria-live 区域朗读 toast 内容。</p>
<span class="cm">// 自定义插件</span>
MeToast.<span class="fn">use</span>({
<span class="fn">name</span>: <span class="s">'my-plugin'</span>,
<span class="fn">install</span>() {
Toast.<span class="fn">on</span>(<span class="s">'afterShow'</span>, (t) => <span class="fn">console</span>.log(t.message));
},
});</pre>
<h2 id="destroy">destroy()</h2> <h2 id="destroy">destroy()</h2>
<p>完全销毁关闭所有 Toast、移除 DOM 容器和样式标签。</p> <p>完全销毁关闭所有 Toast、移除所有 DOM 容器和注入的样式标签、清空内存缓存</p>
<pre>MeToast.<span class="fn">destroy</span>();</pre> <pre>MeToast.<span class="fn">destroy</span>();</pre>
<!-- ===== 配置参考 ===== --> <!-- ===== 配置参考 ===== -->
<h2 id="config">全部配置项</h2> <h2 id="config">全部配置项</h2>
<p>以下配置可用于 <code>configure()</code> 或单个 Toast 的第二个参数</p> <p>以下配置可用于 <code>configure()</code><code>init()</code> 或单个 Toast 方法的 opts 参数。带 <span class="badge badge-new">v2.0</span> 标识的为 v2.0 新增</p>
<table> <table>
<tr><th>配置项</th><th>类型</th><th>默认值</th><th>说明</th></tr> <tr><th>配置项</th><th>类型</th><th>默认值</th><th>说明</th></tr>
<tr><td>position</td><td>string</td><td>'top-right'</td><td>位置:top-left/center/rightbottom-left/center/right</td></tr> <tr><td>position</td><td>string</td><td>'top-right'</td><td>位置:top-left / top-center / top-right / bottom-left / bottom-center / bottom-right</td></tr>
<tr><td>duration</td><td>number</td><td>4000</td><td>显示时长(ms)0=不自动关闭</td></tr> <tr><td>duration</td><td>number</td><td>4000</td><td>显示时长(ms)0=不自动关闭</td></tr>
<tr><td>max</td><td>number</td><td>6</td><td>时最多显示条数</td></tr> <tr><td>max</td><td>number</td><td>6</td><td>一位置最多同时显示条数,超出则关闭最早的</td></tr>
<tr><td>gap</td><td>number</td><td>12</td><td>Toast 之间的间距(px)</td></tr> <tr><td>gap</td><td>number</td><td>12</td><td>Toast 之间的间距(px)</td></tr>
<tr><td>offset</td><td>number</td><td>24</td><td>容器边距(px)</td></tr> <tr><td>offset</td><td>number</td><td>24</td><td>容器到屏幕边缘的距离(px)</td></tr>
<tr><td>pauseOnHover</td><td>boolean</td><td>true</td><td>悬停时暂停计时</td></tr> <tr><td>pauseOnHover</td><td>boolean</td><td>true</td><td>鼠标悬停时暂停 duration 倒计时和进度条</td></tr>
<tr><td>closeOnClick</td><td>boolean</td><td>true</td><td>点击 Toast 关闭</td></tr> <tr><td>closeOnClick</td><td>boolean</td><td>true</td><td>点击 Toast 任意位置关闭。关闭按钮始终触发关闭</td></tr>
<tr><td>draggable</td><td>boolean</td><td>true</td><td>允许拖拽关闭</td></tr> <tr><td>draggable</td><td>boolean</td><td>true</td><td>允许拖拽关闭。拖拽超过 120px 触发关闭</td></tr>
<tr><td>showProgress</td><td>boolean</td><td>true</td><td>显示进度条</td></tr> <tr><td>showProgress</td><td>boolean</td><td>true</td><td>显示 duration 倒计时进度条</td></tr>
<tr><td>progressDirection</td><td>string</td><td>'horizontal'</td><td>进度条方向:horizontal / vertical</td></tr> <tr><td>progressDirection</td><td>string</td><td>'horizontal'</td><td>进度条方向:horizontal(底部水平) / vertical(右侧垂直)</td></tr>
<tr><td>icon</td><td>boolean</td><td>true</td><td>显示类型图标</td></tr> <tr><td>icon</td><td>boolean</td><td>true</td><td>显示类型对应图标(success→对勾等)</td></tr>
<tr><td>closeButton</td><td>boolean</td><td>true</td><td>显示关闭按钮</td></tr> <tr><td>closeButton</td><td>boolean</td><td>true</td><td>显示右上角关闭 × 按钮</td></tr>
<tr><td>theme</td><td>string</td><td>'auto'</td><td>主题:light / dark / auto / warm</td></tr> <tr><td>theme</td><td>string</td><td>'auto'</td><td>主题:light / dark / auto(跟随系统)/ warm / 自定义注册名</td></tr>
<tr><td>animation</td><td>string</td><td>'slide'</td><td>动画效果(见下方列表)</td></tr> <tr><td>animation</td><td>string</td><td>'slide'</td><td>入场动画名称,支持 CSS 动画列表见下</td></tr>
<tr><td>zIndex</td><td>number</td><td>9999</td><td>CSS z-index</td></tr> <tr><td>zIndex</td><td>number</td><td>9999</td><td>容器 CSS z-index</td></tr>
<tr><td>width</td><td>number/string</td><td>360</td><td>Toast 宽度(px)</td></tr> <tr><td>width</td><td>number|string</td><td>360</td><td>Toast 宽度。数字表示 px</td></tr>
<tr><td>className</td><td>string</td><td>''</td><td>附加 CSS 类名</td></tr> <tr><td>className</td><td>string</td><td>''</td><td>附加到 Toast 元素上的 CSS 类名</td></tr>
<tr><td>style</td><td>object</td><td>{}</td><td>内联样式对象</td></tr> <tr><td>style</td><td>object</td><td>{}</td><td>附加到 Toast 元素上的内联样式对象</td></tr>
<tr><td>locale</td><td>string</td><td>'zh-CN'</td><td>语言代码</td></tr> <tr><td>locale</td><td>string</td><td>'zh-CN'</td><td>语言代码zh-CN / en-US 等)</td></tr>
<tr><td>resetTimerOnUpdate</td><td>boolean</td><td>false</td><td>update()时重置计时器 <span class="badge badge-new">v2.0</span></td></tr> <tr><td>resetTimerOnUpdate <span class="badge badge-new">v2.0</span></td><td>boolean</td><td>false</td><td>调用 update() 时重置 duration 倒计时</td></tr>
<tr><td>notifyWhenHidden</td><td>boolean</td><td>false</td><td>页面不可见时发系统通知 <span class="badge badge-new">v2.0</span></td></tr> <tr><td>notifyWhenHidden <span class="badge badge-new">v2.0</span></td><td>boolean</td><td>false</td><td>页面不可见时自动通过 Notification API 发送系统通知</td></tr>
<tr><td>render</td><td>function</td><td></td><td>自定义渲染函数 <span class="badge badge-new">v2.0</span></td></tr> <tr><td>render <span class="badge badge-new">v2.0</span></td><td>function</td><td></td><td>自定义渲染函数 <code>(toast) => htmlString</code>,完全接管 DOM 构建</td></tr>
</table> </table>
<h2 id="callbacks">回调函数</h2> <h2 id="callbacks">回调函数</h2>
<table> <table>
<tr><th>回调</th><th>签名</th><th>触发时机</th></tr> <tr><th>回调</th><th>签名</th><th>触发时机</th></tr>
<tr><td>onShow</td><td>(toast) => void</td><td>Toast 显示</td></tr> <tr><td>onShow</td><td>(toast: ToastInstance) => void</td><td>Toast DOM 创建并播放入场动画</td></tr>
<tr><td>onClose</td><td>(toast) => void</td><td>Toast 关闭后</td></tr> <tr><td>onClose</td><td>(toast: ToastInstance) => void</td><td>Toast DOM 被移除后(离场动画完成时)</td></tr>
<tr><td>onClick</td><td>(toast) => void</td><td>Toast 被点击时</td></tr> <tr><td>onClick</td><td>(toast: ToastInstance) => void</td><td>Toast 被点击时closeOnClick 为 true 时还会自动关闭)</td></tr>
<tr><td>onUpdate</td><td>(toast) => void</td><td>Toast 内容更新后 <span class="badge badge-new">v2.0</span></td></tr> <tr><td>onUpdate <span class="badge badge-new">v2.0</span></td><td>(toast: ToastInstance) => void</td><td>Toast 内容通过 update() 更新后</td></tr>
</table> </table>
<h2 id="animations">动画列表</h2> <h2 id="animations">动画列表</h2>
<p>配置 <code>animation</code> 的值,支持以下 CSS 动画。未在此列表中的值将 fallback 到 slide。</p>
<table> <table>
<tr><th>名称</th><th>效果</th><th>时长</th></tr> <tr><th>名称</th><th>效果</th><th>时长</th></tr>
<tr><td>slide</td><td>从右侧滑入 + 回弹</td><td>400ms</td></tr> <tr><td>slide</td><td>从右侧滑入 + 回弹</td><td>400ms</td></tr>
<tr><td>fade</td><td>纯淡入 (blur→清晰)</td><td>500ms</td></tr> <tr><td>fade</td><td>纯淡入 + blur→清晰</td><td>500ms</td></tr>
<tr><td>scale</td><td>弹性放大 (0.55→1.07→1)</td><td>450ms</td></tr> <tr><td>scale</td><td>弹性放大 (0.55→1.07→1)</td><td>450ms</td></tr>
<tr><td>bounce</td><td>从天而降四段弹跳</td><td>650ms</td></tr> <tr><td>bounce</td><td>从天而降四段弹跳</td><td>650ms</td></tr>
<tr><td>flip</td><td>3D 翻转入场 + 回摆</td><td>500ms</td></tr> <tr><td>flip</td><td>3D 翻转入场 + 回摆</td><td>500ms</td></tr>
@@ -323,7 +466,7 @@ MeToast.<span class="fn">use</span>({
<pre><span class="cm">// 内置主题</span> <pre><span class="cm">// 内置主题</span>
light <span class="cm">— 白色玻璃质感</span> light <span class="cm">— 白色玻璃质感</span>
dark <span class="cm">— 深色玻璃质感</span> dark <span class="cm">— 深色玻璃质感</span>
auto <span class="cm">— 跟随系统</span> auto <span class="cm">— 跟随系统主题设置</span>
warm <span class="cm">— 暖色调</span> warm <span class="cm">— 暖色调</span>
<span class="cm">// 注册自定义主题</span> <span class="cm">// 注册自定义主题</span>
@@ -343,7 +486,6 @@ MeToast.themes.<span class="fn">switchTheme</span>(<span class="s">'ocean'</span
<script src="../dist/metona-toast.js"></script> <script src="../dist/metona-toast.js"></script>
<script> <script>
MeToast.configure({ position: 'top-right', duration: 4000, theme: 'dark', animation: 'slide' }); MeToast.configure({ position: 'top-right', duration: 4000, theme: 'dark', animation: 'slide' });
// 侧边栏高亮
document.querySelectorAll('.sidebar a[href^="#"]').forEach(a => { document.querySelectorAll('.sidebar a[href^="#"]').forEach(a => {
a.addEventListener('click', () => { a.addEventListener('click', () => {
document.querySelectorAll('.sidebar a').forEach(x => x.classList.remove('active')); document.querySelectorAll('.sidebar a').forEach(x => x.classList.remove('active'));
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 303 B

+39
View File
@@ -3,6 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<title>MetonaToast — 轻量精致的 Toast 通知库</title> <title>MetonaToast — 轻量精致的 Toast 通知库</title>
<meta name="description" content="MetonaToast 是轻量、零依赖、精致美观的 Toast 通知库。80+ 图标类型、11 种动画、主题系统、国际化、插件架构。"> <meta name="description" content="MetonaToast 是轻量、零依赖、精致美观的 Toast 通知库。80+ 图标类型、11 种动画、主题系统、国际化、插件架构。">
<style> <style>
@@ -136,6 +137,44 @@
</div> </div>
</main> </main>
<section class="container">
<h2 class="section-title">环境支持</h2>
<p class="section-desc">所有现代浏览器原生支持,无需 polyfill</p>
<div class="env-grid" style="display:grid; grid-template-columns:repeat(auto-fill,minmax(165px,1fr)); gap:12px;">
<div class="feature" style="text-align:center;padding:20px 16px;">
<div style="font-size:28px;margin-bottom:6px;">🌐</div>
<h3>Chrome</h3>
<p>64+</p>
</div>
<div class="feature" style="text-align:center;padding:20px 16px;">
<div style="font-size:28px;margin-bottom:6px;">🦊</div>
<h3>Firefox</h3>
<p>63+</p>
</div>
<div class="feature" style="text-align:center;padding:20px 16px;">
<div style="font-size:28px;margin-bottom:6px;">🧭</div>
<h3>Safari</h3>
<p>11+</p>
</div>
<div class="feature" style="text-align:center;padding:20px 16px;">
<div style="font-size:28px;margin-bottom:6px;">🪟</div>
<h3>Edge</h3>
<p>79+</p>
</div>
<div class="feature" style="text-align:center;padding:20px 16px;">
<div style="font-size:28px;margin-bottom:6px;">📦</div>
<h3>Node.js</h3>
<p>18+</p>
</div>
<div class="feature" style="text-align:center;padding:20px 16px;">
<div style="font-size:28px;margin-bottom:6px;">📘</div>
<h3>TypeScript</h3>
<p>4.5+</p>
</div>
</div>
<p style="text-align:center;color:var(--muted);font-size:13px;margin-top:16px">核心依赖:Web Animations API · Pointer Events · CSS Grid · CSS Custom Properties</p>
</section>
<section class="container"> <section class="container">
<h2 class="section-title">快速开始</h2> <h2 class="section-title">快速开始</h2>
<p class="section-desc">浏览器 window 上仅注册两个全局变量:<code>MeToast</code><code>Met</code>,完全等价</p> <p class="section-desc">浏览器 window 上仅注册两个全局变量:<code>MeToast</code><code>Met</code>,完全等价</p>