Toast

ToastGitHub
一条简洁的消息,向用户提供信息或反馈。

用法

使用 useToast 组合式函数在您的应用程序中显示 toast。

<script setup lang="ts">
const toast = useToast()

function addToCalendar() {
  const eventDate = new Date(Date.now() + Math.random() * 31536000000)
  const formattedDate = eventDate.toLocaleDateString('en-US', {
    month: 'short',
    day: 'numeric',
    year: 'numeric'
  })

  toast.add({
    title: 'Event added to calendar',
    description: `This event is scheduled for ${formattedDate}.`,
    icon: 'i-lucide-calendar-days'
  })
}
</script>

<template>
  <UButton
    label="Add to calendar"
    color="neutral"
    variant="outline"
    icon="i-lucide-plus"
    @click="addToCalendar"
  />
</template>
确保您的应用使用 App 组件进行包裹,该组件使用了我们的Toaster组件,该组件使用了ToastProvider组件(来自 Reka UI)。
您可以查看 App 组件的 toaster 属性,以了解如何全局配置 Toaster。

标题

title 字段传递给 toast.add 方法以显示标题。

<script setup lang="ts">
const props = defineProps<{
  title: string
}>()

const toast = useToast()

function showToast() {
  toast.add(props)
}
</script>

<template>
  <UButton label="Show toast" color="neutral" variant="outline" @click="showToast" />
</template>

描述

description 字段传递给 toast.add 方法以显示描述。

<script setup lang="ts">
const props = defineProps<{
  title: string
  description: string
}>()

const toast = useToast()

function showToast() {
  toast.add(props)
}
</script>

<template>
  <UButton label="Show toast" color="neutral" variant="outline" @click="showToast" />
</template>

Icon

icon 字段传递给 toast.add 方法以显示一个 Icon

<script setup lang="ts">
const props = defineProps<{
  icon: string
}>()

const toast = useToast()

function showToast() {
  toast.add({
    title: 'Uh oh! Something went wrong.',
    description: 'There was a problem with your request.',
    icon: props.icon
  })
}
</script>

<template>
  <UButton label="Show toast" color="neutral" variant="outline" @click="showToast" />
</template>

Avatar

avatar 字段传递给 toast.add 方法以显示一个 Avatar

<script setup lang="ts">
import type { AvatarProps } from '@nuxt/ui'

const props = defineProps<{
  avatar: AvatarProps
}>()

const toast = useToast()

function showToast() {
  toast.add({
    title: 'User invited',
    description: 'benjamincanac was invited to the team.',
    avatar: props.avatar
  })
}
</script>

<template>
  <UButton label="Invite user" color="neutral" variant="outline" @click="showToast" />
</template>

颜色

color 字段传递给 toast.add 方法以更改 Toast 的颜色。

<script setup lang="ts">
import type { ToastProps } from '@nuxt/ui'

const props = defineProps<{
  color: ToastProps['color']
}>()

const toast = useToast()

function showToast() {
  toast.add({
    title: 'Uh oh! Something went wrong.',
    description: 'There was a problem with your request.',
    icon: 'i-lucide-wifi',
    color: props.color
  })
}
</script>

<template>
  <UButton label="Show toast" color="neutral" variant="outline" @click="showToast" />
</template>

关闭

传递 close 字段来自定义或隐藏关闭 Button(使用 false 值)。

<script setup lang="ts">
const toast = useToast()

function showToast() {
  toast.add({
    title: 'Uh oh! Something went wrong.',
    description: 'There was a problem with your request.',
    icon: 'i-lucide-wifi',
    close: {
      color: 'primary',
      variant: 'outline',
      class: 'rounded-full'
    }
  })
}
</script>

<template>
  <UButton label="Show toast" color="neutral" variant="outline" @click="showToast" />
</template>

关闭图标

传递 closeIcon 字段来自定义关闭按钮的 Icon。默认值为 i-lucide-x

<script setup lang="ts">
const props = defineProps<{
  closeIcon: string
}>()

const toast = useToast()

function showToast() {
  toast.add({
    title: 'Uh oh! Something went wrong.',
    description: 'There was a problem with your request.',
    closeIcon: props.closeIcon
  })
}
</script>

<template>
  <UButton label="Show toast" color="neutral" variant="outline" @click="showToast" />
</template>
你可以在 app.config.ts 中的 ui.icons.close 键下全局自定义此图标。
你可以在 vite.config.ts 中的 ui.icons.close 键下全局自定义此图标。

操作

传递 actions 字段以向 Toast 添加一些 Button 操作。

<script setup lang="ts">
const toast = useToast()

const props = defineProps<{
  description: string
}>()

function showToast() {
  toast.add({
    title: 'Uh oh! Something went wrong.',
    description: props.description,
    actions: [{
      icon: 'i-lucide-refresh-cw',
      label: 'Retry',
      color: 'neutral',
      variant: 'outline',
      onClick: (e) => {
        e?.stopPropagation()
      }
    }]
  })
}
</script>

<template>
  <UButton label="Show toast" color="neutral" variant="outline" @click="showToast" />
</template>

Progress

传递 progress 字段来自定义或隐藏 Progress 条(使用 false 值)。

Progress 条默认继承 Toast 的颜色,但您可以使用 progress.color 字段覆盖它。
<script setup lang="ts">
const toast = useToast()

function showToast() {
  toast.add({
    title: 'Uh oh! Something went wrong.',
    description: 'There was a problem with your request.',
    icon: 'i-lucide-wifi',
    progress: false
  })
}
</script>

<template>
  <UButton label="Show toast" color="neutral" variant="outline" @click="showToast" />
</template>

Orientation

orientation 字段传递给 toast.add 方法以更改 Toast 的方向。

<script setup lang="ts">
const toast = useToast()

const props = defineProps<{
  orientation: 'horizontal' | 'vertical'
}>()

function showToast() {
  toast.add({
    title: 'Uh oh! Something went wrong.',
    orientation: props.orientation,
    actions: [{
      icon: 'i-lucide-refresh-cw',
      label: 'Retry',
      color: 'neutral',
      variant: 'outline',
      onClick: (e) => {
        e?.stopPropagation()
      }
    }]
  })
}
</script>

<template>
  <UButton label="Show toast" color="neutral" variant="outline" @click="showToast" />
</template>

示例

Nuxt UI 提供了一个 App 组件,用于包装你的应用,提供全局配置。

更改全局位置

更改 App 组件上的 toaster.position 属性以更改 toasts 的位置。

app.vue
<script setup lang="ts">
const toaster = { position: 'bottom-right' }
</script>

<template>
  <UApp :toaster="toaster">
    <NuxtPage />
  </UApp>
</template>
<script setup lang="ts">
const toast = useToast()

function addToCalendar() {
  const eventDate = new Date(Date.now() + Math.random() * 31536000000)
  const formattedDate = eventDate.toLocaleDateString('en-US', {
    month: 'short',
    day: 'numeric',
    year: 'numeric'
  })

  toast.add({
    title: 'Event added to calendar',
    description: `This event is scheduled for ${formattedDate}.`,
    icon: 'i-lucide-calendar-days'
  })
}
</script>

<template>
  <UButton
    label="Add to calendar"
    color="neutral"
    variant="outline"
    icon="i-lucide-plus"
    @click="addToCalendar"
  />
</template>
在此示例中,我们使用 AppConfig 来全局配置 Toaster 组件的 position 属性。

更改全局持续时间

更改 App 组件上的 toaster.duration 属性以更改 toasts 的持续时间。

app.vue
<script setup lang="ts">
const toaster = { duration: 5000 }
</script>

<template>
  <UApp :toaster="toaster">
    <NuxtPage />
  </UApp>
</template>
<script setup lang="ts">
const toast = useToast()

function addToCalendar() {
  const eventDate = new Date(Date.now() + Math.random() * 31536000000)
  const formattedDate = eventDate.toLocaleDateString('en-US', {
    month: 'short',
    day: 'numeric',
    year: 'numeric'
  })

  toast.add({
    title: 'Event added to calendar',
    description: `This event is scheduled for ${formattedDate}.`,
    icon: 'i-lucide-calendar-days'
  })
}
</script>

<template>
  <UButton
    label="Add to calendar"
    color="neutral"
    variant="outline"
    icon="i-lucide-plus"
    @click="addToCalendar"
  />
</template>
在此示例中,我们使用 AppConfig 来全局配置 Toaster 组件的 duration 属性。

更改全局最大数量 即将推出

更改 App 组件上的 toaster.max 属性以更改一次显示的 toasts 的最大数量。

app.vue
<script setup lang="ts">
const toaster = { max: 3 }
</script>

<template>
  <UApp :toaster="toaster">
    <NuxtPage />
  </UApp>
</template>
<script setup lang="ts">
const toast = useToast()

function addToCalendar() {
  const eventDate = new Date(Date.now() + Math.random() * 31536000000)
  const formattedDate = eventDate.toLocaleDateString('en-US', {
    month: 'short',
    day: 'numeric',
    year: 'numeric'
  })

  toast.add({
    title: 'Event added to calendar',
    description: `This event is scheduled for ${formattedDate}.`,
    icon: 'i-lucide-calendar-days'
  })
}
</script>

<template>
  <UButton
    label="Add to calendar"
    color="neutral"
    variant="outline"
    icon="i-lucide-plus"
    @click="addToCalendar"
  />
</template>
在此示例中,我们使用 AppConfig 来全局配置 Toaster 组件的 max 属性。

堆叠的 toasts

App 组件上的 toaster.expand 属性设置为 false 以显示堆叠的 toasts(灵感来自Sonner).

app.vue
<script setup lang="ts">
const toaster = { expand: true }
</script>

<template>
  <UApp :toaster="toaster">
    <NuxtPage />
  </UApp>
</template>
您可以将鼠标悬停在 toasts 上以展开它们。这也会暂停 toasts 的计时器。
<script setup lang="ts">
const toast = useToast()

function addToCalendar() {
  const eventDate = new Date(Date.now() + Math.random() * 31536000000)
  const formattedDate = eventDate.toLocaleDateString('en-US', {
    month: 'short',
    day: 'numeric',
    year: 'numeric'
  })

  toast.add({
    title: 'Event added to calendar',
    description: `This event is scheduled for ${formattedDate}.`,
    icon: 'i-lucide-calendar-days'
  })
}
</script>

<template>
  <UButton
    label="Add to calendar"
    color="neutral"
    variant="outline"
    icon="i-lucide-plus"
    @click="addToCalendar"
  />
</template>
在此示例中,我们使用 AppConfig 来全局配置 Toaster 组件的 expand 属性。

API

属性

属性默认值类型
as

'li'

any

此组件应渲染为的元素或组件。

title

string | VNode<RendererNode, RendererElement, {[key: string]: any;}) |(): VNode<RendererNode, RendererElement, {[key: string]: any;})

description

string | VNode<RendererNode, RendererElement, {[key: string]: any;}) |(): VNode<RendererNode, RendererElement, {[key: string]: any;})

图标

字符串 | 对象

avatar

AvatarProps

color

'主要'

"primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral"

orientation

'vertical'

"horizontal" | "vertical"

内容与操作之间的方向。

close

true

布尔值 | 部分<ButtonProps>

显示一个关闭按钮来关闭 toast。 { size: 'md', color: 'neutral', variant: 'link' }

closeIcon

appConfig.ui.icons.close

字符串 | 对象

关闭按钮中显示的图标。

actions

ButtonProps[]

显示操作列表

  • 当方向为 vertical 时,在标题和描述下方
  • 当方向为 horizontal 时,在关闭按钮旁边 { size: 'xs' }
progress

true

boolean | Pick<ProgressProps, "color" | "ui">

显示一个进度条,显示 toast 的剩余持续时间。 { size: 'sm' }

defaultOpen

boolean

对话框初始渲染时的打开状态。当您不需要控制其打开状态时使用。

open

boolean

对话框的可控打开状态。可以绑定为 v-model:open

type

"foreground" | "background"

控制 toast 的可访问性。

对于由用户操作产生的 toasts,选择 foreground。由后台任务生成的 toasts 应使用 background

duration

number

toast 保持可见的时间(毫秒)。覆盖 ToastProvider 的值。

ui

{ root?: ClassNameValue; wrapper?: ClassNameValue; title?: ClassNameValue; description?: ClassNameValue; icon?: ClassNameValue; avatar?: ClassNameValue; avatarSize?: ClassNameValue; actions?: ClassNameValue; progress?: ClassNameValue; close?: ClassNameValue;}

插槽

插槽类型
前置

{}

title

{}

description

{}

actions

{}

close

{ ui: {}; }

事件

事件类型
pause

[]

escapeKeyDown

[event: KeyboardEvent]

resume

[]

swipeStart

[event: SwipeEvent]

swipeMove

[event: SwipeEvent]

swipeCancel

[event: SwipeEvent]

swipeEnd

[event: SwipeEvent]

update:open

[value: boolean]

主题

app.config.ts
export default defineAppConfig({
  ui: {
    toast: {
      slots: {
        root: 'relative group overflow-hidden bg-default shadow-lg rounded-lg ring ring-default p-4 flex gap-2.5 focus:outline-none',
        wrapper: 'w-0 flex-1 flex flex-col',
        title: 'text-sm font-medium text-highlighted',
        description: 'text-sm text-muted',
        icon: 'shrink-0 size-5',
        avatar: 'shrink-0',
        avatarSize: '2xl',
        actions: 'flex gap-1.5 shrink-0',
        progress: 'absolute inset-x-0 bottom-0',
        close: 'p-0'
      },
      variants: {
        color: {
          primary: {
            root: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary',
            icon: 'text-primary'
          },
          secondary: {
            root: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-secondary',
            icon: 'text-secondary'
          },
          success: {
            root: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-success',
            icon: 'text-success'
          },
          info: {
            root: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-info',
            icon: 'text-info'
          },
          warning: {
            root: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-warning',
            icon: 'text-warning'
          },
          error: {
            root: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-error',
            icon: 'text-error'
          },
          neutral: {
            root: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-inverted',
            icon: 'text-highlighted'
          }
        },
        orientation: {
          horizontal: {
            root: 'items-center',
            actions: 'items-center'
          },
          vertical: {
            root: 'items-start',
            actions: 'items-start mt-2.5'
          }
        },
        title: {
          true: {
            description: 'mt-1'
          }
        }
      },
      defaultVariants: {
        color: 'primary'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        toast: {
          slots: {
            root: 'relative group overflow-hidden bg-default shadow-lg rounded-lg ring ring-default p-4 flex gap-2.5 focus:outline-none',
            wrapper: 'w-0 flex-1 flex flex-col',
            title: 'text-sm font-medium text-highlighted',
            description: 'text-sm text-muted',
            icon: 'shrink-0 size-5',
            avatar: 'shrink-0',
            avatarSize: '2xl',
            actions: 'flex gap-1.5 shrink-0',
            progress: 'absolute inset-x-0 bottom-0',
            close: 'p-0'
          },
          variants: {
            color: {
              primary: {
                root: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary',
                icon: 'text-primary'
              },
              secondary: {
                root: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-secondary',
                icon: 'text-secondary'
              },
              success: {
                root: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-success',
                icon: 'text-success'
              },
              info: {
                root: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-info',
                icon: 'text-info'
              },
              warning: {
                root: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-warning',
                icon: 'text-warning'
              },
              error: {
                root: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-error',
                icon: 'text-error'
              },
              neutral: {
                root: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-inverted',
                icon: 'text-highlighted'
              }
            },
            orientation: {
              horizontal: {
                root: 'items-center',
                actions: 'items-center'
              },
              vertical: {
                root: 'items-start',
                actions: 'items-start mt-2.5'
              }
            },
            title: {
              true: {
                description: 'mt-1'
              }
            }
          },
          defaultVariants: {
            color: 'primary'
          }
        }
      }
    })
  ]
})

更新日志

61b60— 功能:允许传递组件而不是名称 (#4766)

5cb65— 特性:导入 @nuxt/ui-pro 组件

a8af8— fix: add type for progress ui prop (#4677)

ec569— feat: progress bar with Progress component

1d052— fix: only show progress when open

be41a— 修复:移除按钮默认md尺寸 (#4357)

3bf5a— fix: calc height on next tick

92632— feat: add progress prop to hide progress bar (#4125)

e6e51— fix:class 应该优先于 ui 属性

50863— fix: display actions when using slots

39c86— fix:@nuxt/module-builder 升级后重构类型(#3855)

b9983— 修复:改进泛型类型 (#3331)

f4c41— 修复:防止不必要的 close 实例化