rewrite: toast stacking with daisyui toast container
- module-level reactive toast list in composables/toast (setToast signature unchanged, 13 call sites untouched) - multiple toasts stack simultaneously in daisyUI toast container, each auto-dismisses (3s) with close button - TransitionGroup enter/leave animation (transform/opacity, honors reduced-motion) - drop provide/inject queue that blocked consecutive toasts
This commit is contained in:
@@ -1,24 +1,35 @@
|
||||
import { inject } from 'vue'
|
||||
import type { InjectionKey } from 'vue'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export type ToastType = 'info' | 'success' | 'error'
|
||||
|
||||
export type ToastMessage = {
|
||||
message: string
|
||||
type?: ToastType
|
||||
duration?: number
|
||||
export type ToastItem = {
|
||||
id: number
|
||||
message: string
|
||||
type: ToastType
|
||||
duration: number
|
||||
}
|
||||
|
||||
export type ToastContext = {
|
||||
setToast: (message: string, type?: ToastType, duration?: number) => void
|
||||
// 模块级共享状态:所有活动 toast 堆叠展示,互不阻塞
|
||||
const toasts = ref<ToastItem[]>([])
|
||||
let seed = 0
|
||||
|
||||
function dismiss(id: number) {
|
||||
toasts.value = toasts.value.filter(t => t.id !== id)
|
||||
}
|
||||
|
||||
export const ToastKey: InjectionKey<ToastContext> = Symbol('toast')
|
||||
export function setToast(message: string, type: ToastType = 'info', duration = 3000) {
|
||||
const id = ++seed
|
||||
toasts.value.push({ id, message, type, duration })
|
||||
if (duration > 0) {
|
||||
setTimeout(() => dismiss(id), duration)
|
||||
}
|
||||
}
|
||||
|
||||
export function useToast(): ToastContext {
|
||||
const ctx = inject(ToastKey)
|
||||
if (!ctx) {
|
||||
throw new Error('ToastContext 未提供:请在 App 根组件 provide(ToastKey, ...)')
|
||||
}
|
||||
return ctx
|
||||
export function useToast() {
|
||||
return { setToast }
|
||||
}
|
||||
|
||||
// 供 Toast 组件渲染使用
|
||||
export function useToasts() {
|
||||
return { toasts, dismiss }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user