聊天消息列表

AI SDKGitHub
显示聊天消息列表,旨在与 Vercel AI SDK 无缝协作。

用法

ChatMessages 组件使用默认插槽或 messages prop 显示 ChatMessage 组件列表。

<template>
  <UChatMessages>
    <UChatMessage
      v-for="(message, index) in messages"
      :key="index"
      v-bind="message"
    />
  </UChatMessages>
</template>
此组件专为 AI 聊天机器人设计,具有以下功能:
  • 加载时初始滚动到底部 (shouldScrollToBottom).
  • 新消息到达时持续向下滚动 (shouldAutoScroll).
  • 当用户向上滚动时,会出现一个“自动滚动”按钮,允许用户跳回最新消息 (autoScroll).
  • 助手处理时显示加载指示器 (status).
  • 提交的消息会滚动到视口顶部,并且最后一条用户消息的高度会动态调整。

消息

使用 messages prop 显示聊天消息列表。

你好,你怎么样?
我很好,谢谢你的询问!今天有什么可以帮你的吗?
东京现在天气如何?
根据最新数据,东京目前天气晴朗,气温约 24°C (75°F)。今天天气很好,天空晴朗。
<script setup lang="ts">
const messages = ref([
  {
    id: '6045235a-a435-46b8-989d-2df38ca2eb47',
    role: 'user',
    parts: [
      {
        type: 'text',
        text: 'Hello, how are you?'
      }
    ]
  },
  {
    id: '7a92b3c1-d5f8-4e76-b8a9-3c1e5fb2e0d8',
    role: 'assistant',
    parts: [
      {
        type: 'text',
        text: 'I am doing well, thank you for asking! How can I assist you today?'
      }
    ]
  },
  {
    id: '9c84d6a7-8b23-4f12-a1d5-e7f3b9c05e2a',
    role: 'user',
    parts: [
      {
        type: 'text',
        text: 'What is the current weather in Tokyo?'
      }
    ]
  },
  {
    id: 'b2e5f8c3-a1d9-4e67-b3f2-c9d8e7a6b5f4',
    role: 'assistant',
    parts: [
      {
        type: 'text',
        text: "Based on the latest data, Tokyo is currently experiencing sunny weather with temperatures around 24°C (75°F). It's a beautiful day with clear skies."
      }
    ]
  }
])
</script>

<template>
  <UChatMessages :messages="messages" />
</template>

状态

使用 status prop 在助手处理时显示视觉指示器。

你好,你怎么样?
<script setup lang="ts">
const messages = ref([
  {
    id: '6045235a-a435-46b8-989d-2df38ca2eb47',
    role: 'user',
    parts: [
      {
        type: 'text',
        text: 'Hello, how are you?'
      }
    ]
  }
])
</script>

<template>
  <UChatMessages status="submitted" :messages="messages" />
</template>
以下是 AI SDK v5 Chat 类中不同状态的详细信息
  • submitted:消息已发送到 API,我们正在等待响应流的开始。
  • streaming:响应正在积极地从 API 流入,接收数据块。
  • ready:已收到并处理完整响应;可以提交新的用户消息。
  • error:API 请求期间发生错误,导致无法成功完成。

用户

使用 user prop 更改 user 消息的 ChatMessage props。默认为

  • side: 'right'
  • variant: 'soft'
你好,你怎么样?
我很好,谢谢你的询问!今天有什么可以帮你的吗?
东京现在天气如何?
根据最新数据,东京目前天气晴朗,气温约 24°C (75°F)。今天天气很好,天空晴朗。
<script setup lang="ts">
const messages = ref([
  {
    id: '6045235a-a435-46b8-989d-2df38ca2eb47',
    role: 'user',
    parts: [
      {
        type: 'text',
        text: 'Hello, how are you?'
      }
    ]
  },
  {
    id: '7a92b3c1-d5f8-4e76-b8a9-3c1e5fb2e0d8',
    role: 'assistant',
    parts: [
      {
        type: 'text',
        text: 'I am doing well, thank you for asking! How can I assist you today?'
      }
    ]
  },
  {
    id: '9c84d6a7-8b23-4f12-a1d5-e7f3b9c05e2a',
    role: 'user',
    parts: [
      {
        type: 'text',
        text: 'What is the current weather in Tokyo?'
      }
    ]
  },
  {
    id: 'b2e5f8c3-a1d9-4e67-b3f2-c9d8e7a6b5f4',
    role: 'assistant',
    parts: [
      {
        type: 'text',
        text: "Based on the latest data, Tokyo is currently experiencing sunny weather with temperatures around 24°C (75°F). It's a beautiful day with clear skies."
      }
    ]
  }
])
</script>

<template>
  <UChatMessages
    :user="{
      side: 'left',
      variant: 'solid',
      avatar: {
        src: 'https://github.com/benjamincanac.png'
      }
    }"
    :messages="messages"
  />
</template>

助手

使用 assistant prop 更改 assistant 消息的 ChatMessage props。默认为

  • side: 'left'
  • variant: 'naked'
你好,你怎么样?
我很好,谢谢你的询问!今天有什么可以帮你的吗?
东京现在天气如何?
根据最新数据,东京目前天气晴朗,气温约 24°C (75°F)。今天天气很好,天空晴朗。
<script setup lang="ts">
const messages = ref([
  {
    id: '6045235a-a435-46b8-989d-2df38ca2eb47',
    role: 'user',
    parts: [
      {
        type: 'text',
        text: 'Hello, how are you?'
      }
    ]
  },
  {
    id: '7a92b3c1-d5f8-4e76-b8a9-3c1e5fb2e0d8',
    role: 'assistant',
    parts: [
      {
        type: 'text',
        text: 'I am doing well, thank you for asking! How can I assist you today?'
      }
    ]
  },
  {
    id: '9c84d6a7-8b23-4f12-a1d5-e7f3b9c05e2a',
    role: 'user',
    parts: [
      {
        type: 'text',
        text: 'What is the current weather in Tokyo?'
      }
    ]
  },
  {
    id: 'b2e5f8c3-a1d9-4e67-b3f2-c9d8e7a6b5f4',
    role: 'assistant',
    parts: [
      {
        type: 'text',
        text: "Based on the latest data, Tokyo is currently experiencing sunny weather with temperatures around 24°C (75°F). It's a beautiful day with clear skies."
      }
    ]
  }
])
</script>

<template>
  <UChatMessages
    :assistant="{
      side: 'left',
      variant: 'outline',
      avatar: {
        icon: 'i-lucide-bot'
      },
      actions: [
        {
          label: 'Copy to clipboard',
          icon: 'i-lucide-copy'
        }
      ]
    }"
    :messages="messages"
  />
</template>

自动滚动

使用 auto-scroll prop 自定义或隐藏在聊天顶部滚动时显示的自动滚动按钮(值为 false)。默认为

  • color: 'neutral'
  • variant: 'outline'

您可以传递 Button 组件的任何属性来自定义它。

你好,你怎么样?
我很好,谢谢你的询问!今天有什么可以帮你的吗?
东京现在天气如何?
根据最新数据,东京目前天气晴朗,气温约 24°C (75°F)。今天天气很好,天空晴朗。本周剩余时间的天气预报显示周四有小雨,周末气温将逐渐升至 28°C。湿度水平适中,约 65%,风速较小,东南风 8 公里/小时。空气质量良好,指数为 42。紫外线指数较高,为 7,因此如果您计划在户外活动,建议涂抹防晒霜。日出时间为上午 5:24,日落时间为下午 6:48,东京今天大约有 13 小时 24 分钟的日照时间。月亮目前处于盈凸月阶段。
你能推荐一些京都受欢迎的旅游景点吗?
京都以其美丽的寺庙、传统茶馆和花园而闻名。一些热门景点包括金阁寺(Kinkaku-ji,金阁),其令人惊叹的金箔外观倒映在镜池中;伏见稻荷大社(Fushimi Inari Shrine),其成千上万的朱红色鸟居门蜿蜒而上;岚山竹林(Arashiyama Bamboo Grove),高耸的竹秆营造出一种超凡脱俗的氛围;清水寺(Kiyomizu-dera Temple),坐落在山坡上,可俯瞰城市全景;以及历史悠久的祗园区(Gion district),在那里您可能会在狭窄的石板路上看到艺妓们急匆匆地赶往晚间约会,街道两旁是传统的木制町屋。
<script setup lang="ts">
const messages = ref([
  {
    id: '6045235a-a435-46b8-989d-2df38ca2eb47',
    role: 'user',
    parts: [
      {
        type: 'text',
        text: 'Hello, how are you?'
      }
    ]
  },
  {
    id: '7a92b3c1-d5f8-4e76-b8a9-3c1e5fb2e0d8',
    role: 'assistant',
    parts: [
      {
        type: 'text',
        text: 'I am doing well, thank you for asking! How can I assist you today?'
      }
    ]
  },
  {
    id: '9c84d6a7-8b23-4f12-a1d5-e7f3b9c05e2a',
    role: 'user',
    parts: [
      {
        type: 'text',
        text: 'What is the current weather in Tokyo?'
      }
    ]
  },
  {
    id: 'b2e5f8c3-a1d9-4e67-b3f2-c9d8e7a6b5f4',
    role: 'assistant',
    parts: [
      {
        type: 'text',
        text: "Based on the latest data, Tokyo is currently experiencing sunny weather with temperatures around 24°C (75°F). It's a beautiful day with clear skies. The forecast for the rest of the week shows a slight chance of rain on Thursday, with temperatures gradually rising to 28°C by the weekend. Humidity levels are moderate at around 65%, and wind speeds are light at 8 km/h from the southeast. Air quality is good with an index of 42. The UV index is high at 7, so it's recommended to wear sunscreen if you're planning to spend time outdoors. Sunrise was at 5:24 AM and sunset will be at 6:48 PM, giving Tokyo approximately 13 hours and 24 minutes of daylight today. The moon is currently in its waxing gibbous phase."
      }
    ]
  },
  {
    id: 'c3e5f8c3-a1d9-4e67-b3f2-c9d8e7a6b5f4',
    role: 'user',
    parts: [
      {
        type: 'text',
        text: 'Can you recommend some popular tourist attractions in Kyoto?'
      }
    ]
  },
  {
    id: 'd4f5g8c3-a1d9-4e67-b3f2-c9d8e7a6b5f4',
    role: 'assistant',
    parts: [
      {
        type: 'text',
        text: 'Kyoto is known for its beautiful temples, traditional tea houses, and gardens. Some popular attractions include Kinkaku-ji (Golden Pavilion) with its stunning gold leaf exterior reflecting in the mirror pond, Fushimi Inari Shrine with its thousands of vermilion torii gates winding up the mountainside, Arashiyama Bamboo Grove where towering stalks create an otherworldly atmosphere, Kiyomizu-dera Temple perched on a hillside offering panoramic views of the city, and the historic Gion district where you might spot geisha hurrying to evening appointments through narrow stone-paved streets lined with traditional wooden machiya houses.'
      }
    ]
  }
])
</script>

<template>
  <UChatMessages
    :auto-scroll="{
      color: 'neutral',
      variant: 'outline'
    }"
    :should-scroll-to-bottom="false"
    :messages="messages"
  />
</template>

自动滚动图标

使用 auto-scroll-icon prop 自定义自动滚动按钮 Icon。默认为 i-lucide-arrow-down

你好,你怎么样?
我很好,谢谢你的询问!今天有什么可以帮你的吗?
东京现在天气如何?
根据最新数据,东京目前天气晴朗,气温约 24°C (75°F)。今天天气很好,天空晴朗。本周剩余时间的天气预报显示周四有小雨,周末气温将逐渐升至 28°C。湿度水平适中,约 65%,风速较小,东南风 8 公里/小时。空气质量良好,指数为 42。紫外线指数较高,为 7,因此如果您计划在户外活动,建议涂抹防晒霜。日出时间为上午 5:24,日落时间为下午 6:48,东京今天大约有 13 小时 24 分钟的日照时间。月亮目前处于盈凸月阶段。
你能推荐一些京都受欢迎的旅游景点吗?
京都以其美丽的寺庙、传统茶馆和花园而闻名。一些热门景点包括金阁寺(Kinkaku-ji,金阁),其令人惊叹的金箔外观倒映在镜池中;伏见稻荷大社(Fushimi Inari Shrine),其成千上万的朱红色鸟居门蜿蜒而上;岚山竹林(Arashiyama Bamboo Grove),高耸的竹秆营造出一种超凡脱俗的氛围;清水寺(Kiyomizu-dera Temple),坐落在山坡上,可俯瞰城市全景;以及历史悠久的祗园区(Gion district),在那里您可能会在狭窄的石板路上看到艺妓们急匆匆地赶往晚间约会,街道两旁是传统的木制町屋。
<script setup lang="ts">
const messages = ref([
  {
    id: '6045235a-a435-46b8-989d-2df38ca2eb47',
    role: 'user',
    parts: [
      {
        type: 'text',
        text: 'Hello, how are you?'
      }
    ]
  },
  {
    id: '7a92b3c1-d5f8-4e76-b8a9-3c1e5fb2e0d8',
    role: 'assistant',
    parts: [
      {
        type: 'text',
        text: 'I am doing well, thank you for asking! How can I assist you today?'
      }
    ]
  },
  {
    id: '9c84d6a7-8b23-4f12-a1d5-e7f3b9c05e2a',
    role: 'user',
    parts: [
      {
        type: 'text',
        text: 'What is the current weather in Tokyo?'
      }
    ]
  },
  {
    id: 'b2e5f8c3-a1d9-4e67-b3f2-c9d8e7a6b5f4',
    role: 'assistant',
    parts: [
      {
        type: 'text',
        text: "Based on the latest data, Tokyo is currently experiencing sunny weather with temperatures around 24°C (75°F). It's a beautiful day with clear skies. The forecast for the rest of the week shows a slight chance of rain on Thursday, with temperatures gradually rising to 28°C by the weekend. Humidity levels are moderate at around 65%, and wind speeds are light at 8 km/h from the southeast. Air quality is good with an index of 42. The UV index is high at 7, so it's recommended to wear sunscreen if you're planning to spend time outdoors. Sunrise was at 5:24 AM and sunset will be at 6:48 PM, giving Tokyo approximately 13 hours and 24 minutes of daylight today. The moon is currently in its waxing gibbous phase."
      }
    ]
  },
  {
    id: 'c3e5f8c3-a1d9-4e67-b3f2-c9d8e7a6b5f4',
    role: 'user',
    parts: [
      {
        type: 'text',
        text: 'Can you recommend some popular tourist attractions in Kyoto?'
      }
    ]
  },
  {
    id: 'd4f5g8c3-a1d9-4e67-b3f2-c9d8e7a6b5f4',
    role: 'assistant',
    parts: [
      {
        type: 'text',
        text: 'Kyoto is known for its beautiful temples, traditional tea houses, and gardens. Some popular attractions include Kinkaku-ji (Golden Pavilion) with its stunning gold leaf exterior reflecting in the mirror pond, Fushimi Inari Shrine with its thousands of vermilion torii gates winding up the mountainside, Arashiyama Bamboo Grove where towering stalks create an otherworldly atmosphere, Kiyomizu-dera Temple perched on a hillside offering panoramic views of the city, and the historic Gion district where you might spot geisha hurrying to evening appointments through narrow stone-paved streets lined with traditional wooden machiya houses.'
      }
    ]
  }
])
</script>

<template>
  <UChatMessages
    auto-scroll-icon="i-lucide-chevron-down"
    :should-scroll-to-bottom="false"
    :messages="messages"
  />
</template>
您可以在 app.config.ts 中的 ui.icons.arrowDown 键下全局自定义此图标。
您可以在 vite.config.ts 中的 ui.icons.arrowDown 键下全局自定义此图标。

应自动滚动

使用 should-auto-scroll prop 启用/禁用消息流式传输时的连续自动滚动。默认为 false

<template>
  <UChatMessages :messages="messages" should-auto-scroll />
</template>

应滚动到底部

使用 should-scroll-to-bottom prop 启用/禁用组件挂载时自动滚动到底部。默认为 true

<template>
  <UChatMessages :messages="messages" :should-scroll-to-bottom="false" />
</template>

示例

这些聊天组件旨在与 Vercel AI SDKAI SDK v5 配合使用。
请查看 GitHub 上的 AI 聊天模板源代码,了解实际示例。

在页面内

将 ChatMessages 组件与 AI SDK v5 中的 Chat 类一起使用,以在页面中显示聊天消息列表。

传递 messages prop 和 status prop,它们将用于自动滚动和指示器显示。

pages/[id].vue
<script setup lang="ts">
import { Chat } from '@ai-sdk/vue'
import { getTextFromMessage } from '@nuxt/ui/utils/ai'

const input = ref('')

const chat = new Chat({
  onError(error) {
    console.error(error)
  }
})

function onSubmit() {
  chat.sendMessage({ text: input.value })

  input.value = ''
}
</script>

<template>
  <UDashboardPanel>
    <template #body>
      <UContainer>
        <UChatMessages :messages="chat.messages" :status="chat.status">
          <template #content="{ message }">
            <MDC :value="getTextFromMessage(message)" :cache-key="message.id" class="*:first:mt-0 *:last:mb-0" />
          </template>
        </UChatMessages>
      </UContainer>
    </template>

    <template #footer>
      <UContainer class="pb-4 sm:pb-6">
        <UChatPrompt v-model="input" :error="chat.error" @submit="onSubmit">
          <UChatPromptSubmit :status="chat.status" @stop="chat.stop()" @reload="chat.regenerate()" />
        </UChatPrompt>
      </UContainer>
    </template>
  </UDashboardPanel>
</template>
在此示例中,我们使用来自@nuxtjs/mdcMDC 组件来渲染消息内容。getTextFromMessage 实用程序从 AI SDK V5 消息部分提取文本内容。由于 Nuxt UI 提供了预先设置样式的 prose 组件,因此您的内容将自动设置样式。

带指示器插槽

您可以自定义当状态为 submitted 时出现的加载指示器。

你好!你能帮我一下吗?
<template>
  <UChatMessages
    :messages="[
      {
        id: '1',
        role: 'user',
        parts: [{ type: 'text', text: 'Hello! Can you help me with something?' }]
      }
    ]"
    status="submitted"
    :should-scroll-to-bottom="false"
    :user="{
      avatar: { icon: 'i-lucide-user' },
      variant: 'soft',
      side: 'right'
    }"
  >
    <template #indicator>
      <UButton
        class="px-0"
        color="neutral"
        variant="link"
        loading
        loading-icon="i-lucide-loader"
        label="Thinking..."
      />
    </template>
  </UChatMessages>
</template>

API

属性

属性默认值类型
messagesUIMessage<unknown, UIDataTypes, UITools>[]
status"error" | "submitted" | "streaming" | "ready"
shouldAutoScrollfalseboolean

消息流式传输时是否自动滚动到底部。

shouldScrollToBottomtrueboolean

挂载时是否滚动到底部。

autoScrolltrueboolean | Omit<ButtonProps, LinkPropsKeys>

显示自动滚动按钮。{ size: 'md', color: 'neutral', variant: 'outline' }

autoScrollIconappConfig.ui.icons.arrowDownany

自动滚动按钮中显示的图标。

userPick<ChatMessageProps, "ui" | "variant" | "icon" | "avatar" | "side" | "actions">

user 消息 prop。{ side: 'right', variant: 'soft' }

assistantPick<ChatMessageProps, "ui" | "variant" | "icon" | "avatar" | "side" | "actions">

assistant 消息 prop。{ side: 'left', variant: 'naked' }

紧凑falseboolean

以紧凑样式渲染消息。这在使用 UChatPalette 时自动完成。

spacingOffset0number

最后一条消息的间距偏移量(以像素为单位)。当提示固定时(例如),这可能很有用。

ui{ root?: ClassNameValue; indicator?: ClassNameValue; viewport?: ClassNameValue; autoScroll?: ClassNameValue; }

插槽

插槽类型
前置{ avatar: (AvatarProps & { [key: string]: any; }) | undefined; ui: object; } & { message: UIMessage<unknown, UIDataTypes, UITools>; }
内容ChatMessageProps & { message: UIMessage<unknown, UIDataTypes, UITools>; }
actions{ actions: (Omit<ButtonProps, "onClick"> & { onClick?: ((e: MouseEvent, message: UIMessage<unknown, UIDataTypes, UITools>) => void) | undefined; })[] | undefined; } & { message: UIMessage<unknown, UIDataTypes, UITools>; }
default{}
indicator{ ui: object; }
viewport{ ui: object; }
您可以在 ChatMessages 中使用 ChatMessage 组件的所有插槽,它们会自动转发,允许您在使用 messages prop 时自定义单个消息。
<script setup lang="ts">
import { getTextFromMessage } from '@nuxt/ui/utils/ai'
</script>

<template>
  <UChatMessages :messages="messages" :status="status">
    <template #content="{ message }">
      <MDC :value="getTextFromMessage(message)" :cache-key="message.id" class="*:first:mt-0 *:last:mb-0" />
    </template>
  </UChatMessages>
</template>

主题

app.config.ts
export default defineAppConfig({
  ui: {
    chatMessages: {
      slots: {
        root: 'w-full flex flex-col gap-1 flex-1 px-2.5 [&>article]:last-of-type:min-h-(--last-message-height)',
        indicator: 'h-6 flex items-center gap-1 py-3 *:size-2 *:rounded-full *:bg-elevated [&>*:nth-child(1)]:animate-[bounce_1s_infinite] [&>*:nth-child(2)]:animate-[bounce_1s_0.15s_infinite] [&>*:nth-child(3)]:animate-[bounce_1s_0.3s_infinite]',
        viewport: 'absolute inset-x-0 top-[86%] data-[state=open]:animate-[fade-in_200ms_ease-out] data-[state=closed]:animate-[fade-out_200ms_ease-in]',
        autoScroll: 'rounded-full absolute right-1/2 translate-x-1/2 bottom-0'
      },
      variants: {
        compact: {
          true: '',
          false: ''
        }
      }
    }
  }
})
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: {
        chatMessages: {
          slots: {
            root: 'w-full flex flex-col gap-1 flex-1 px-2.5 [&>article]:last-of-type:min-h-(--last-message-height)',
            indicator: 'h-6 flex items-center gap-1 py-3 *:size-2 *:rounded-full *:bg-elevated [&>*:nth-child(1)]:animate-[bounce_1s_infinite] [&>*:nth-child(2)]:animate-[bounce_1s_0.15s_infinite] [&>*:nth-child(3)]:animate-[bounce_1s_0.3s_infinite]',
            viewport: 'absolute inset-x-0 top-[86%] data-[state=open]:animate-[fade-in_200ms_ease-out] data-[state=closed]:animate-[fade-out_200ms_ease-in]',
            autoScroll: 'rounded-full absolute right-1/2 translate-x-1/2 bottom-0'
          },
          variants: {
            compact: {
              true: '',
              false: ''
            }
          }
        }
      }
    })
  ]
})

更新日志

184ea— chore: 减少类型冗余,通过省略操作按钮中的链接属性

dd81d— feat: 添加 data-slot 属性 (#5447)

5b177— feat: 扩展原生 HTML 属性 (#5348)

db737— 修复:允许用户使用 should-auto-scroll 滚动 (#5252)

63c0a— feat: 在使用的 slot prop 中暴露 ui (#5207)

240bc— 修复:定义用户和助手 ui prop 类型 (#5234)

ff67f— 修复:使用 parts 深度监听以处理流式传输

0db62— 修复:确保内容在滚动前渲染

c00bf— 修复:用插槽包裹指示器 (#5036)

3173b— fix: proxySlots 响应性 (#4969)

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

de782— feat!: 升级 ai-sdk 到 v5 (#4698)

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