Appearance
Sonner 消息提示
Sonner 组件是一个轻量级的消息提示组件,支持多种类型的提示(成功、错误、警告、信息),可以自定义位置、内容和样式,适用于各种交互反馈场景。
基础用法
Sonner 组件提供了多种使用方式,包括组件实例方法调用、全局 $toast 方法调用、组合式 API useToast() 以及直接导入的全局 toast 对象。
通过插件方法调用
自定义配置
操作方法
实际应用场景
vue
<template>
<div class="sonner-demo">
<div class="demo-section">
<h3 class="section-title">通过插件方法调用</h3>
<div class="demo-content">
<Button @click="showBasicToast">显示基本消息</Button>
<Button type="primary" @click="showTitleToast">带标题的消息</Button>
<Button type="success" @click="showSuccessToast">成功消息</Button>
<Button type="error" @click="showErrorToast">错误消息</Button>
<Button type="warning" @click="showWarningToast">警告消息</Button>
<Button type="info" @click="showInfoToast">信息消息</Button>
</div>
</div>
<div class="demo-section">
<h3 class="section-title">自定义配置</h3>
<div class="demo-content">
<Button @click="showCustomDuration">自定义显示时间</Button>
<Button @click="showUndismissable">不可关闭的消息</Button>
<Button @click="showWithCustomIcon">自定义图标</Button>
</div>
</div>
<div class="demo-section">
<h3 class="section-title">操作方法</h3>
<div class="demo-content">
<Button @click="showMultipleToasts">显示多个消息</Button>
<Button @click="dismissAllToasts">关闭所有消息</Button>
</div>
</div>
<div class="demo-section">
<h3 class="section-title">实际应用场景</h3>
<div class="demo-content">
<Button @click="showFormSubmitDemo">表单提交反馈</Button>
<Button @click="showLoadingDemo">加载状态提示</Button>
<Button @click="showNotificationDemo">系统通知</Button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { inject } from 'vue';
import { Button } from '../../../src/components/Button';
import type { ToastPluginInstance } from '../../../src/components/Sonner/ToastPlugin';
// 使用 inject 获取全局注册的 toast 实例(推荐方式)
const toast = inject<ToastPluginInstance>('toast');
// 检查 toast 是否存在的辅助函数
const safeToast = () => {
if (!toast) {
console.error('Toast 实例未找到,请确保正确注册了 ToastPlugin');
alert('Toast 功能不可用,请刷新页面重试');
return false;
}
return true;
};
// 显示基本消息 - 最简单的消息提示,只包含描述文本
const showBasicToast = () => {
if (!safeToast()) return;
toast.addToast({
description: '这是一条基本的消息提示',
});
};
// 显示带标题的消息 - 包含标题和描述文本的消息
const showTitleToast = () => {
if (!safeToast()) return;
toast.addToast({
title: '提示',
description: '这是一条带标题的消息提示',
});
};
// 显示成功消息 - 快捷方法,用于操作成功的反馈
const showSuccessToast = () => {
if (!safeToast()) return;
toast.success('操作成功', '成功');
};
// 显示错误消息 - 快捷方法,用于操作失败的反馈
const showErrorToast = () => {
if (!safeToast()) return;
toast.error('操作失败,请重试', '错误');
};
// 显示警告消息 - 快捷方法,用于需要用户注意的情况
const showWarningToast = () => {
if (!safeToast()) return;
toast.warning('请注意,这是一条警告消息', '警告');
};
// 显示信息消息 - 快捷方法,用于一般信息的展示
const showInfoToast = () => {
if (!safeToast()) return;
toast.info('这是一条信息提示', '信息');
};
// 自定义显示时间 - 设置消息显示的持续时间(毫秒)
const showCustomDuration = () => {
if (!safeToast()) return;
toast.addToast({
title: '自定义时间',
description: '这条消息将显示 10 秒钟',
duration: 10000,
});
};
// 不可关闭的消息 - 设置为无限持续时间,不会自动关闭
const showUndismissable = () => {
if (!safeToast()) return;
toast.addToast({
title: '重要通知',
description: '这条消息不会自动关闭,请手动关闭',
duration: Infinity,
});
};
// 自定义图标 - 使用指定的图标名称显示自定义图标
const showWithCustomIcon = () => {
if (!safeToast()) return;
toast.addToast({
title: '自定义图标',
description: '这条消息使用了自定义图标',
icon: 'star',
});
};
// 显示多个消息 - 连续显示多条消息,展示消息队列效果
const showMultipleToasts = () => {
if (!safeToast()) return;
for (let i = 0; i < 5; i++) {
toast.addToast({
title: `消息 ${i + 1}`,
description: `这是第 ${i + 1} 条消息`,
duration: 3000 + i * 1000,
// 每条消息使用不同类型
type: ['success', 'info', 'warning', 'error', 'default'][i % 5] as any,
});
}
};
// 关闭所有消息 - 一键关闭当前显示的所有消息
const dismissAllToasts = () => {
if (!safeToast()) return;
toast.dismissAll();
};
// 表单提交反馈演示 - 模拟表单提交过程的消息反馈
const showFormSubmitDemo = () => {
if (!safeToast()) return;
// 显示提交中消息
const loadingToastId = toast.addToast({
title: '提交中',
description: '正在处理您的请求,请稍候...',
type: 'info',
duration: Infinity,
});
// 模拟网络请求延迟
setTimeout(() => {
// 关闭加载消息
toast.dismissToast(loadingToastId);
// 显示成功消息
toast.success('表单已成功提交', '提交成功');
}, 2000);
};
// 加载状态提示演示 - 模拟长时间加载过程的状态更新
const showLoadingDemo = () => {
if (!safeToast()) return;
// 显示初始加载消息
let progress = 0;
const progressToastId = toast.addToast({
title: '加载中',
description: `进度: ${progress}%`,
type: 'info',
duration: Infinity,
});
// 模拟进度更新
const interval = setInterval(() => {
progress += 10;
if (progress >= 100) {
// 完成加载
clearInterval(interval);
toast.updateToast(progressToastId, {
title: '加载完成',
description: '所有内容已成功加载',
type: 'success',
duration: 3000,
});
} else {
// 更新进度
toast.updateToast(progressToastId, {
description: `进度: ${progress}%`,
});
}
}, 500);
};
// 系统通知演示 - 模拟不同时间点收到的系统通知
const showNotificationDemo = () => {
if (!safeToast()) return;
toast.info('您有一封新邮件', '新消息');
setTimeout(() => {
toast.warning('服务器将在30分钟后进行维护', '系统通知');
}, 1000);
setTimeout(() => {
toast.success('数据已自动备份', '备份完成');
}, 2000);
};
</script>
<style scoped>
.sonner-demo {
padding: 20px;
background-color: var(--color-bg-1);
border-radius: 8px;
}
.demo-intro {
font-size: 14px;
color: var(--color-text-3);
margin-bottom: 24px;
line-height: 1.5;
}
.demo-title {
font-size: 24px;
margin-bottom: 16px;
color: var(--color-text-1);
font-weight: 600;
}
.demo-section {
margin-bottom: 32px;
padding: 16px;
background-color: var(--color-bg-2);
border-radius: 6px;
border: 1px solid var(--color-border);
}
.section-title {
font-size: 18px;
margin-bottom: 16px;
color: var(--color-text-1);
font-weight: 500;
}
.demo-content {
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: center;
}
</style>不同类型的消息
Sonner 支持四种预设的消息类型:成功(success)、错误(error)、警告(warning)和信息(info),每种类型都有对应的图标和颜色。
Sonner 消息提示 - 不同类型
Sonner 提供多种消息类型和丰富的自定义选项,满足不同场景下的需求。点击下方按钮查看效果。
基本消息类型
每种类型的消息都有对应的图标和默认样式,可以根据场景选择合适的类型。
自定义样式
通过自定义选项可以控制消息的外观,包括大小、颜色等属性。
交互式消息
交互式消息可以包含操作按钮、链接等元素,提供更丰富的用户体验。
高级应用场景
结合不同功能,可以实现更复杂的交互场景。
vue
<template>
<div class="sonner-demo">
<h2 class="demo-title">Sonner 消息提示 - 不同类型</h2>
<p class="demo-intro">
Sonner 提供多种消息类型和丰富的自定义选项,满足不同场景下的需求。点击下方按钮查看效果。
</p>
<div class="demo-section">
<h3 class="section-title">基本消息类型</h3>
<div class="demo-content">
<Button type="success" @click="showSuccessToasts">显示成功消息</Button>
<Button type="danger" @click="showErrorToasts">显示错误消息</Button>
<Button type="warning" @click="showWarningToasts">显示警告消息</Button>
<Button type="info" @click="showInfoToasts">显示信息消息</Button>
<Button @click="showDefaultToast">显示默认消息</Button>
</div>
<div class="demo-notes">
<p>每种类型的消息都有对应的图标和默认样式,可以根据场景选择合适的类型。</p>
</div>
</div>
<div class="demo-section">
<h3 class="section-title">自定义样式</h3>
<div class="demo-content">
<Button @click="showCustomStyledToasts">显示自定义样式消息</Button>
<Button @click="showSizeVariations">显示不同尺寸消息</Button>
<Button @click="showColorVariations">显示不同颜色消息</Button>
</div>
<div class="demo-notes">
<p>通过自定义选项可以控制消息的外观,包括大小、颜色等属性。</p>
</div>
</div>
<div class="demo-section">
<h3 class="section-title">交互式消息</h3>
<div class="demo-content">
<Button @click="showInteractiveToast">显示交互式消息</Button>
<Button @click="showToastWithAction">带操作按钮的消息</Button>
<Button @click="showToastWithLink">带链接的消息</Button>
</div>
<div class="demo-notes">
<p>交互式消息可以包含操作按钮、链接等元素,提供更丰富的用户体验。</p>
</div>
</div>
<div class="demo-section">
<h3 class="section-title">高级应用场景</h3>
<div class="demo-content">
<Button @click="showConfirmToast">确认对话框</Button>
<Button @click="showProgressToast">进度提示</Button>
<Button @click="showNotificationGroup">通知组</Button>
</div>
<div class="demo-notes">
<p>结合不同功能,可以实现更复杂的交互场景。</p>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { getCurrentInstance } from 'vue';
import { Button } from '../../../src/components/Button';
// 通过 getCurrentInstance 获取全局注册的 $toast 方法
const { proxy } = getCurrentInstance() as any;
const toast = proxy.$toast;
// 显示成功消息示例 - 用于操作成功的场景
const showSuccessToasts = () => {
// 基本成功消息
toast.success('数据已成功保存', '保存成功');
// 延迟显示另一条成功消息
setTimeout(() => {
toast.success('文件上传完成', '上传成功');
}, 1000);
};
// 显示错误消息示例 - 用于操作失败的场景
const showErrorToasts = () => {
// 网络错误示例
toast.error('网络连接失败,请检查网络设置', '连接错误');
// 延迟显示另一条错误消息
setTimeout(() => {
toast.error('文件格式不支持,请选择正确的文件格式', '格式错误');
}, 1000);
};
// 显示警告消息示例 - 用于需要注意的情况
const showWarningToasts = () => {
// 会话过期警告
toast.warning('您的会话将在 5 分钟后过期', '会话提醒');
// 延迟显示另一条警告消息
setTimeout(() => {
toast.warning('此操作将覆盖现有数据,请谨慎操作', '操作警告');
}, 1000);
};
// 显示信息消息示例 - 用于一般信息的展示
const showInfoToasts = () => {
// 系统维护通知
toast.info('系统将在今晚 10 点进行维护', '系统通知');
// 延迟显示另一条信息消息
setTimeout(() => {
toast.info('您有 3 条新消息', '消息提醒');
}, 1000);
};
// 显示默认消息示例 - 通用消息类型
const showDefaultToast = () => {
toast.addToast({
title: '通用通知',
description: '这是一条默认类型的消息提示',
});
};
// 显示自定义样式消息示例
const showCustomStyledToasts = () => {
// 圆角消息
toast.addToast({
title: '圆角消息',
description: '这是一条带有圆角样式的消息提示',
type: 'warning',
className: 'rounded-lg',
});
// 延迟显示阴影消息
setTimeout(() => {
toast.addToast({
title: '阴影消息',
description: '这是一条带有增强阴影的消息提示',
type: 'error',
className: 'shadow-lg',
});
}, 500);
// 延迟显示自定义背景色消息
setTimeout(() => {
toast.addToast({
title: '彩色消息',
description: '这是一条带有自定义背景色的消息提示',
type: 'info',
className: 'bg-gradient-to-r from-blue-500 to-purple-600 text-white',
});
}, 1000);
};
// 显示不同尺寸消息示例
const showSizeVariations = () => {
// 小型消息
toast.addToast({
title: '小型消息',
description: '适合简短的状态提示',
type: 'info',
size: 'small',
});
// 延迟显示中型消息(默认尺寸)
setTimeout(() => {
toast.addToast({
title: '中型消息',
description: '默认尺寸,适合大多数场景',
type: 'success',
});
}, 500);
// 延迟显示大型消息
setTimeout(() => {
toast.addToast({
title: '大型消息',
description: '适合包含更多信息的详细通知,提供更丰富的上下文内容和描述',
type: 'warning',
size: 'large',
});
}, 1000);
};
// 显示不同颜色消息示例
const showColorVariations = () => {
// 主要颜色
toast.addToast({
title: '主要颜色',
description: '使用品牌主色的消息',
type: 'success',
});
// 辅助颜色
setTimeout(() => {
toast.addToast({
title: '辅助颜色',
description: '使用辅助色的消息',
type: 'info',
});
}, 500);
// 自定义颜色
setTimeout(() => {
toast.addToast({
title: '自定义颜色',
description: '使用自定义CSS类的消息',
className: 'bg-gradient-to-r from-pink-500 to-orange-500 text-white',
});
}, 1000);
};
// 显示交互式消息示例
const showInteractiveToast = () => {
// 点击消息本身触发回调
const toastId = toast.addToast({
title: '点击查看详情',
description: '点击此消息查看更多信息',
type: 'info',
duration: Infinity,
});
// 这里可以添加实际的点击处理逻辑
// 注意:实际的点击处理在Sonner组件内部实现
// 可以在组件中添加自定义的点击事件逻辑
};
// 显示带操作按钮的消息示例
const showToastWithAction = () => {
// 模拟带操作按钮的消息
toast.addToast({
title: '需要确认',
description: '是否继续执行此操作?',
type: 'warning',
duration: Infinity,
// 注意:实际的按钮需要在Sonner组件内部或通过其他方式实现
});
// 显示后续操作的结果消息
setTimeout(() => {
toast.success('操作已确认', '已完成');
}, 3000);
};
// 显示带链接的消息示例
const showToastWithLink = () => {
toast.addToast({
title: '查看详情',
description: '点击查看完整报告',
type: 'info',
duration: 8000,
// 注意:实际的链接需要在Sonner组件内部或通过其他方式实现
});
};
// 显示确认对话框示例
const showConfirmToast = () => {
const confirmToastId = toast.addToast({
title: '确认删除',
description: '确定要删除此项目吗?此操作不可撤销。',
type: 'warning',
duration: Infinity,
});
// 模拟用户确认操作
setTimeout(() => {
toast.dismissToast(confirmToastId);
toast.success('项目已成功删除', '删除完成');
}, 2000);
};
// 显示进度提示示例
const showProgressToast = () => {
// 模拟文件上传进度
const progressToastId = toast.addToast({
title: '文件上传中',
description: '正在上传文档.pdf...',
type: 'info',
duration: Infinity,
});
// 模拟上传完成
setTimeout(() => {
toast.updateToast(progressToastId, {
title: '上传完成',
description: '文档.pdf 已成功上传',
type: 'success',
duration: 3000,
});
}, 2000);
};
// 显示通知组示例
const showNotificationGroup = () => {
// 模拟收到多条相关通知
toast.info('您有新的系统更新', '系统通知');
setTimeout(() => toast.success('更新已下载', '准备安装'), 800);
setTimeout(() => toast.warning('点击立即安装', '更新提示'), 1600);
setTimeout(() => toast.success('系统更新完成', '已更新至最新版本'), 2400);
};
</script>
<style scoped>
.sonner-demo {
padding: 20px;
background-color: var(--color-bg-1);
border-radius: 8px;
}
.demo-intro {
font-size: 14px;
color: var(--color-text-3);
margin-bottom: 24px;
line-height: 1.5;
}
.demo-title {
font-size: 24px;
margin-bottom: 16px;
color: var(--color-text-1);
font-weight: 600;
}
.demo-section {
margin-bottom: 32px;
padding: 16px;
background-color: var(--color-bg-2);
border-radius: 6px;
border: 1px solid var(--color-border);
}
.section-title {
font-size: 18px;
margin-bottom: 16px;
color: var(--color-text-1);
font-weight: 500;
}
.demo-content {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 12px;
}
.demo-notes {
font-size: 13px;
color: var(--color-text-4);
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid var(--color-border);
}
.demo-notes p {
margin: 0;
line-height: 1.4;
}
/* 自定义样式类 */
.rounded-lg {
border-radius: 12px !important;
}
.shadow-lg {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05) !important;
}
/* 自定义渐变背景色 */
.bg-gradient-to-r {
background-image: linear-gradient(to right, var(--tw-gradient-stops)) !important;
}
.from-blue-500 {
--tw-gradient-from: #3b82f6;
--tw-gradient-to: transparent;
}
.to-purple-600 {
--tw-gradient-to: #8b5cf6;
}
.from-pink-500 {
--tw-gradient-from: #ec4899;
--tw-gradient-to: transparent;
}
.to-orange-500 {
--tw-gradient-to: #f97316;
}
.text-white {
color: white !important;
}
</style>自定义位置
可以通过设置 position 属性来改变消息提示的位置,支持多种位置选项。
Sonner 消息提示 - 自定义位置
Sonner 支持在屏幕的不同位置显示消息提示,可以根据应用场景选择合适的位置。
基本位置选项
点击按钮查看不同位置的消息效果,每个位置使用独立的 Sonner 实例。
位置组合演示
同时在所有位置显示不同类型的消息,展示多实例协同工作效果。
实时位置切换
top-right
右上角
左上角
顶部居中
右下角
左下角
底部居中
选择位置后显示消息,可以直观比较不同位置的显示效果。
偏移量控制
偏移量:16px
调整消息距离屏幕边缘的偏移量,适用于需要避开其他固定元素的场景。
高级位置应用
结合实际业务场景,展示不同位置的应用策略。
vue
<template>
<div class="sonner-demo">
<h2 class="demo-title">Sonner 消息提示 - 自定义位置</h2>
<p class="demo-intro">
Sonner 支持在屏幕的不同位置显示消息提示,可以根据应用场景选择合适的位置。
</p>
<div class="demo-section">
<h3 class="section-title">基本位置选项</h3>
<div class="demo-content">
<Button @click="showTopRight">右上角</Button>
<Button @click="showTopLeft">左上角</Button>
<Button @click="showTopCenter">顶部居中</Button>
<Button @click="showBottomRight">右下角</Button>
<Button @click="showBottomLeft">左下角</Button>
<Button @click="showBottomCenter">底部居中</Button>
</div>
<div class="demo-notes">
<p>点击按钮查看不同位置的消息效果,每个位置使用独立的 Sonner 实例。</p>
</div>
</div>
<div class="demo-section">
<h3 class="section-title">位置组合演示</h3>
<div class="demo-content">
<Button @click="showAllPositions">显示所有位置的消息</Button>
</div>
<div class="demo-notes">
<p>同时在所有位置显示不同类型的消息,展示多实例协同工作效果。</p>
</div>
</div>
<div class="demo-section">
<h3 class="section-title">实时位置切换</h3>
<div class="demo-content">
<Select v-model="selectedPosition" placeholder="选择位置" style="width: 200px;">
<Option value="top-right">右上角</Option>
<Option value="top-left">左上角</Option>
<Option value="top-center">顶部居中</Option>
<Option value="bottom-right">右下角</Option>
<Option value="bottom-left">左下角</Option>
<Option value="bottom-center">底部居中</Option>
</Select>
<Button @click="showMessageAtSelectedPosition">显示消息</Button>
</div>
<div class="demo-notes">
<p>选择位置后显示消息,可以直观比较不同位置的显示效果。</p>
</div>
</div>
<div class="demo-section">
<h3 class="section-title">偏移量控制</h3>
<div class="demo-content">
<div class="offset-control">
<span>偏移量:{{ offsetValue }}px</span>
<Input
v-model="offsetValue"
type="number"
:min="0"
:max="100"
:step="8"
style="width: 100px; margin: 0 8px;"
/>
</div>
<Button @click="updateOffset">更新偏移量</Button>
</div>
<div class="demo-notes">
<p>调整消息距离屏幕边缘的偏移量,适用于需要避开其他固定元素的场景。</p>
</div>
</div>
<div class="demo-section">
<h3 class="section-title">高级位置应用</h3>
<div class="demo-content">
<Button @click="showPositionGroup">分组位置通知</Button>
<Button @click="showPriorityNotifications">优先级通知位置</Button>
<Button @click="showContextSensitive">上下文敏感位置</Button>
</div>
<div class="demo-notes">
<p>结合实际业务场景,展示不同位置的应用策略。</p>
</div>
</div>
<!-- 位置演示用的 Sonner 组件 -->
<Sonner ref="topRightSonner" position="top-right" :offset="offsetValue" />
<Sonner ref="topLeftSonner" position="top-left" :offset="offsetValue" />
<Sonner ref="topCenterSonner" position="top-center" :offset="offsetValue" />
<Sonner ref="bottomRightSonner" position="bottom-right" :offset="offsetValue" />
<Sonner ref="bottomLeftSonner" position="bottom-left" :offset="offsetValue" />
<Sonner ref="bottomCenterSonner" position="bottom-center" :offset="offsetValue" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { Button } from '../../../src/components/Button';
import { Select, Option } from '../../../src/components/Select';
import { Input } from '../../../src/components/Input';
import { Sonner } from '../../../src/components/Sonner';
import type { ToastPluginInstance } from '../../../src/components/Sonner/types';
// 引用不同位置的 Sonner 组件实例
const topRightSonner = ref<ToastPluginInstance>();
const topLeftSonner = ref<ToastPluginInstance>();
const topCenterSonner = ref<ToastPluginInstance>();
const bottomRightSonner = ref<ToastPluginInstance>();
const bottomLeftSonner = ref<ToastPluginInstance>();
const bottomCenterSonner = ref<ToastPluginInstance>();
// 选中的位置
const selectedPosition = ref('top-right');
// 偏移量值
const offsetValue = ref(16);
// 获取位置名称的映射表
const positionNames: Record<string, string> = {
'top-right': '右上角',
'top-left': '左上角',
'top-center': '顶部居中',
'bottom-right': '右下角',
'bottom-left': '左下角',
'bottom-center': '底部居中',
};
// 在右上角显示消息
const showTopRight = () => {
topRightSonner.value?.addToast({
title: '右上角消息',
description: '这条消息显示在右上角,适用于不干扰用户主操作区的提示',
type: 'success',
icon: 'check-check',
duration: 4000,
});
};
// 在左上角显示消息
const showTopLeft = () => {
topLeftSonner.value?.addToast({
title: '左上角消息',
description: '这条消息显示在左上角,适合与左侧导航结合的界面',
type: 'info',
icon: 'bell',
duration: 4000,
});
};
// 在顶部居中显示消息
const showTopCenter = () => {
topCenterSonner.value?.addToast({
title: '顶部居中消息',
description: '这条消息显示在顶部居中位置,适合重要通知',
type: 'warning',
icon: 'triangle-alert',
duration: 4000,
});
};
// 在右下角显示消息
const showBottomRight = () => {
bottomRightSonner.value?.addToast({
title: '右下角消息',
description: '这条消息显示在右下角,适合移动设备或需要从下向上显示的场景',
type: 'error',
icon: 'circle-alert',
duration: 4000,
});
};
// 在左下角显示消息
const showBottomLeft = () => {
bottomLeftSonner.value?.addToast({
title: '左下角消息',
description: '这条消息显示在左下角,适合与底部导航结合的界面',
type: 'success',
icon: 'check-check',
duration: 4000,
});
};
// 在底部居中显示消息
const showBottomCenter = () => {
bottomCenterSonner.value?.addToast({
title: '底部居中消息',
description: '这条消息显示在底部居中位置,类似原生应用的通知样式',
type: 'info',
icon: 'bell',
duration: 4000,
});
};
// 显示所有位置的消息
const showAllPositions = () => {
// 依次在各个位置显示消息
showTopRight();
setTimeout(() => showTopLeft(), 300);
setTimeout(() => showTopCenter(), 600);
setTimeout(() => showBottomRight(), 900);
setTimeout(() => showBottomLeft(), 1200);
setTimeout(() => showBottomCenter(), 1500);
};
// 在选中的位置显示消息
const showMessageAtSelectedPosition = () => {
const message = {
title: `${getPositionName(selectedPosition.value)}消息`,
description: `这条消息显示在${getPositionName(selectedPosition.value)}位置`,
type: 'info',
icon: 'bell',
duration: 4000,
};
// 根据选择的位置显示消息
switch (selectedPosition.value) {
case 'top-right':
topRightSonner.value?.addToast(message);
break;
case 'top-left':
topLeftSonner.value?.addToast(message);
break;
case 'top-center':
topCenterSonner.value?.addToast(message);
break;
case 'bottom-right':
bottomRightSonner.value?.addToast(message);
break;
case 'bottom-left':
bottomLeftSonner.value?.addToast(message);
break;
case 'bottom-center':
bottomCenterSonner.value?.addToast(message);
break;
}
};
// 更新偏移量
const updateOffset = () => {
// 注意:这里只是演示偏移量的概念
// 实际的偏移量更新需要通过重新渲染组件来实现
// 这里我们可以显示一条消息确认偏移量已更新
topRightSonner.value?.addToast({
title: '偏移量已更新',
description: `当前偏移量: ${offsetValue.value}px`,
type: 'success',
duration: 2000,
});
};
// 显示分组位置通知
const showPositionGroup = () => {
// 业务消息显示在右上角
topRightSonner.value?.addToast({
title: '新订单',
description: '您有一个新的订单等待处理',
type: 'success',
duration: 5000,
});
// 系统消息显示在左上角
setTimeout(() => {
topLeftSonner.value?.addToast({
title: '系统通知',
description: '系统将在今晚 10 点进行维护',
type: 'info',
duration: 5000,
});
}, 1000);
// 警告消息显示在顶部居中
setTimeout(() => {
topCenterSonner.value?.addToast({
title: '重要提醒',
description: '您的账户余额不足,请及时充值',
type: 'warning',
duration: 5000,
});
}, 2000);
};
// 显示优先级通知位置
const showPriorityNotifications = () => {
// 低优先级:右上角
topRightSonner.value?.addToast({
title: '低优先级通知',
description: '数据同步已完成',
type: 'info',
duration: 3000,
});
// 中优先级:右下角
setTimeout(() => {
bottomRightSonner.value?.addToast({
title: '中优先级通知',
description: '您有3条未读消息',
type: 'success',
duration: 4000,
});
}, 1000);
// 高优先级:顶部居中
setTimeout(() => {
topCenterSonner.value?.addToast({
title: '高优先级通知',
description: '系统检测到异常活动',
type: 'error',
duration: 6000,
});
}, 2000);
};
// 显示上下文敏感位置
const showContextSensitive = () => {
// 模拟表单提交成功(底部居中,不干扰用户继续浏览)
bottomCenterSonner.value?.addToast({
title: '表单提交成功',
description: '您的信息已保存',
type: 'success',
duration: 3000,
});
// 模拟操作反馈(与操作按钮同侧的右下角)
setTimeout(() => {
bottomRightSonner.value?.addToast({
title: '操作已完成',
description: '文件已成功上传',
type: 'success',
duration: 3000,
});
}, 1500);
};
// 获取位置名称
const getPositionName = (position: string): string => {
return positionNames[position] || position;
};
</script>
<style scoped>
.sonner-demo {
padding: 20px;
background-color: var(--color-bg-1);
border-radius: 8px;
}
.demo-intro {
font-size: 14px;
color: var(--color-text-3);
margin-bottom: 24px;
line-height: 1.5;
}
.demo-title {
font-size: 24px;
margin-bottom: 16px;
color: var(--color-text-1);
font-weight: 600;
}
.demo-section {
margin-bottom: 32px;
padding: 16px;
background-color: var(--color-bg-2);
border-radius: 6px;
border: 1px solid var(--color-border);
}
.section-title {
font-size: 18px;
margin-bottom: 16px;
color: var(--color-text-1);
font-weight: 500;
}
.demo-content {
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: flex-end;
margin-bottom: 12px;
}
.demo-notes {
font-size: 13px;
color: var(--color-text-4);
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid var(--color-border);
}
.demo-notes p {
margin: 0;
line-height: 1.4;
}
.offset-control {
display: flex;
align-items: center;
gap: 8px;
background-color: var(--color-bg-1);
padding: 8px 12px;
border-radius: 4px;
border: 1px solid var(--color-border);
}
.offset-control span {
font-size: 14px;
color: var(--color-text-2);
}
</style>简单调用方式
Sonner 消息提示 - 简单调用方式
Sonner 提供了更简洁的调用方式,包括组合式 API 和全局 toast 对象,让消息提示更加便捷易用。
使用组合式 API (useToast)
通过 useToast() 组合式 API 获取 toast 实例,然后调用相应的方法显示不同类型的消息。
使用全局 toast 对象
直接导入全局 toast 对象并调用其方法,适合在任何地方快速显示消息。
高级用法对比
对比不同调用方式的效果,包括详细配置选项的使用。
实际应用场景
在实际业务场景中使用不同的调用方式处理交互反馈。
vue
<template>
<div class="sonner-demo">
<h2 class="demo-title">Sonner 消息提示 - 简单调用方式</h2>
<p class="demo-intro">
Sonner 提供了更简洁的调用方式,包括组合式 API 和全局 toast
对象,让消息提示更加便捷易用。
</p>
<div class="demo-section">
<h3 class="section-title">使用组合式 API (useToast)</h3>
<div class="demo-content">
<Button @click="showSuccessWithToastApi">成功消息</Button>
<Button @click="showErrorWithToastApi">错误消息</Button>
<Button @click="showWarningWithToastApi">警告消息</Button>
<Button @click="showInfoWithToastApi">信息消息</Button>
</div>
<div class="demo-notes">
<p>
通过 useToast() 组合式 API 获取 toast
实例,然后调用相应的方法显示不同类型的消息。
</p>
</div>
</div>
<div class="demo-section">
<h3 class="section-title">使用全局 toast 对象</h3>
<div class="demo-content">
<Button @click="showSuccessWithGlobalToast">成功消息</Button>
<Button @click="showErrorWithGlobalToast">错误消息</Button>
<Button @click="showWarningWithGlobalToast">警告消息</Button>
<Button @click="showInfoWithGlobalToast">信息消息</Button>
</div>
<div class="demo-notes">
<p>直接导入全局 toast 对象并调用其方法,适合在任何地方快速显示消息。</p>
</div>
</div>
<div class="demo-section">
<h3 class="section-title">高级用法对比</h3>
<div class="demo-content">
<Button @click="compareMethods">对比调用方式</Button>
</div>
<div class="demo-notes">
<p>对比不同调用方式的效果,包括详细配置选项的使用。</p>
</div>
</div>
<div class="demo-section">
<h3 class="section-title">实际应用场景</h3>
<div class="demo-content">
<Button @click="submitForm">表单提交</Button>
<Button @click="loadData">加载数据</Button>
<Button @click="deleteItem">删除项目</Button>
</div>
<div class="demo-notes">
<p>在实际业务场景中使用不同的调用方式处理交互反馈。</p>
</div>
</div>
<!-- 为演示提供默认位置的 Sonner 组件 -->
<Sonner position="top-right" />
</div>
</template>
<script setup lang="ts">
import { Button } from '../../../src/components/Button';
import { Sonner } from '../../../src/components/Sonner';
import { useToast, toast } from '../../../src/components/Sonner';
// 使用组合式 API 获取 toast 实例
const toastApi = useToast();
// === 组合式 API 使用示例 ===
// 显示成功消息
const showSuccessWithToastApi = () => {
toastApi.success('操作成功', '提示');
};
// 显示错误消息
const showErrorWithToastApi = () => {
toastApi.error('操作失败', '错误');
};
// 显示警告消息
const showWarningWithToastApi = () => {
toastApi.warning('操作可能存在风险', '警告');
};
// 显示信息消息
const showInfoWithToastApi = () => {
toastApi.info('这是一条提示信息', '信息');
};
// === 全局 toast 对象使用示例 ===
// 显示成功消息
const showSuccessWithGlobalToast = () => {
toast.success('操作成功', '提示');
};
// 显示错误消息
const showErrorWithGlobalToast = () => {
toast.error('操作失败', '错误');
};
// 显示警告消息
const showWarningWithGlobalToast = () => {
toast.warning('操作可能存在风险', '警告');
};
// 显示信息消息
const showInfoWithGlobalToast = () => {
toast.info('这是一条提示信息', '信息');
};
// === 对比调用方式 ===
const compareMethods = () => {
// 使用组合式 API 带详细配置
toastApi.addToast({
title: '组合式 API 调用',
description: '使用 useToast() 组合式 API 并配置详细选项',
type: 'success',
duration: 4000,
icon: 'check-check',
size: 'large',
style: { backgroundColor: 'rgba(72, 187, 120, 0.1)' },
});
// 使用全局 toast 对象带详细配置
setTimeout(() => {
toast.addToast({
title: '全局 toast 对象调用',
description: '直接导入 toast 对象并配置详细选项',
type: 'info',
duration: 4000,
icon: 'bell',
size: 'large',
style: { backgroundColor: 'rgba(59, 130, 246, 0.1)' },
});
}, 1500);
};
// === 实际应用场景示例 ===
// 表单提交场景
const submitForm = () => {
// 模拟提交中
const loadingToastId = toast.addToast({
title: '提交中',
description: '正在处理您的请求...',
type: 'info',
duration: Infinity, // 不会自动关闭
dismissible: false, // 禁止手动关闭
icon: 'circle-loader',
});
// 模拟网络请求延迟
setTimeout(() => {
// 关闭加载提示
toast.dismissToast(loadingToastId);
// 显示成功消息
toast.success('表单提交成功', '成功');
}, 2000);
};
// 加载数据场景
const loadData = () => {
// 使用组合式 API 显示加载状态
const loadingToastId = toastApi.addToast({
title: '加载中',
description: '正在加载数据...',
type: 'info',
duration: Infinity,
icon: 'circle-loader',
});
// 模拟数据加载
setTimeout(() => {
toastApi.dismissToast(loadingToastId);
toastApi.info('数据加载完成', '提示');
}, 1500);
};
// 删除项目场景
const deleteItem = () => {
toast.warning('确定要删除此项目吗?', '警告');
// 模拟用户确认删除
setTimeout(() => {
toast.success('项目已成功删除', '成功');
}, 1000);
};
</script>
<style scoped>
.sonner-demo {
padding: 20px;
background-color: var(--color-bg-1);
border-radius: 8px;
}
.demo-intro {
font-size: 14px;
color: var(--color-text-3);
margin-bottom: 24px;
line-height: 1.5;
}
.demo-title {
font-size: 24px;
margin-bottom: 16px;
color: var(--color-text-1);
font-weight: 600;
}
.demo-section {
margin-bottom: 32px;
padding: 16px;
background-color: var(--color-bg-2);
border-radius: 6px;
border: 1px solid var(--color-border);
}
.section-title {
font-size: 18px;
margin-bottom: 16px;
color: var(--color-text-1);
font-weight: 500;
}
.demo-content {
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: flex-end;
margin-bottom: 12px;
}
.demo-notes {
font-size: 13px;
color: var(--color-text-4);
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid var(--color-border);
}
.demo-notes p {
margin: 0;
line-height: 1.4;
}
</style>自定义内容
除了基本的标题和描述,Sonner 还支持通过插槽自定义内容,以及设置各种样式选项。
Sonner Props
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| position | string | 'top-right' | 消息提示的位置,可选值:'top-right'、'top-left'、'bottom-right'、'bottom-left'、'top-center'、'bottom-center' |
| rtl | boolean | false | 是否使用 RTL 布局 |
| limit | number | 3 | 同时显示的最大消息数量 |
| offset | number | 16 | 消息提示框与屏幕边缘的偏移量 |
| pauseOnHover | boolean | true | 鼠标悬停时是否暂停自动关闭计时器 |
| containerStyle | Record<string, string> | {} | 容器的自定义样式 |
Toast 选项
使用 $toast.addToast() 方法时,可以传递以下选项:
| 选项名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| type | string | 'default' | 消息类型,可选值:'default'、'success'、'error'、'warning'、'info' |
| title | string | - | 消息标题 |
| description | string | - | 消息描述 |
| duration | number | 5000 | 消息显示的持续时间(毫秒),设置为 Infinity 可禁用自动关闭 |
| dismissible | boolean | true | 是否显示关闭按钮 |
| icon | string | - | 自定义图标名称 |
| style | Record<string, string> | {} | 自定义样式 |
| size | string | 'default' | 消息大小,可选值:'small'、'default'、'large' |
| rounded | boolean | false | 是否使用圆角样式 |
| shadow | boolean | false | 是否使用阴影效果 |
| slot | string | - | 自定义内容插槽名称 |
方法
Sonner 组件和 $toast 提供以下方法:
| 方法名 | 参数 | 返回值 | 说明 |
|---|---|---|---|
| addToast | options: Omit<Toast, 'id'> | number | 添加一个自定义消息,返回消息 ID |
| dismissToast | id: number | void | 关闭指定 ID 的消息 |
| dismissAll | - | void | 关闭所有消息 |
| updateToast | id: number, updates: Partial<Toast> | void | 更新指定 ID 的消息 |
| success | message: string, title?: string | number | 显示成功消息 |
| error | message: string, title?: string | number | 显示错误消息 |
| warning | message: string, title?: string | number | 显示警告消息 |
| info | message: string, title?: string | number | 显示信息消息 |
安装和配置
在应用的入口文件中,通常是 main.js 或 main.ts,你需要导入并使用 Sonner 组件:
javascript
import { createApp } from 'vue';
import App from './App.vue';
import Zui from './install';
const app = createApp(App);
app.use(Zui);
app.mount('#app');然后在 App.vue 中添加 Sonner 组件:
vue
<template>
<div class="app">
<Sonner />
<!-- 其他组件 -->
</div>
</template>访问方式
在 Vue 组件中,你可以通过以下方式访问 Sonner:
- 通过
this.$toast(在选项 API 中) - 通过
inject('toast')(在组合 API 中) - 通过直接导入的
useToast()组合式 API - 通过直接导入的全局
toast对象
使用组合式 API
vue
<template>
<Button @click="showSuccessToast">显示成功消息</Button>
</template>
<script setup>
import { useToast } from '../src/components/Sonner';
const toast = useToast();
const showSuccessToast = () => {
toast.success('操作成功', '提示');
};
</script>使用全局 toast 对象
vue
<template>
<Button @click="showErrorToast">显示错误消息</Button>
</template>
<script setup>
import { toast } from '../src/components/Sonner';
const showErrorToast = () => {
toast.error('操作失败', '错误');
};
</script>响应式设计
Sonner 组件会根据屏幕宽度自动调整位置和大小,在移动设备上会自动适应屏幕宽度。