ChatMessagesPRO

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

用法

ChatMessage 组件使用默认插槽或 messages prop 来显示聊天消息列表。

<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',
    content: 'Hello, how are you?'
  },
  {
    id: '7a92b3c1-d5f8-4e76-b8a9-3c1e5fb2e0d8',
    role: 'assistant',
    content: 'I am doing well, thank you for asking! How can I assist you today?'
  },
  {
    id: '9c84d6a7-8b23-4f12-a1d5-e7f3b9c05e2a',
    role: 'user',
    content: 'What is the current weather in Tokyo?'
  },
  {
    id: 'b2e5f8c3-a1d9-4e67-b3f2-c9d8e7a6b5f4',
    role: 'assistant',
    content:
      "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',
    content: 'Hello, how are you?'
  }
])
</script>

<template>
  <UChatMessages status="submitted" :messages="messages" />
</template>
以下是 useChat 可组合函数发送的不同状态的详细信息
  • submitted: 消息已发送到 API,我们正在等待响应流的开始。
  • streaming: 响应正在从 API 主动流式传输,接收数据块。
  • ready: 已接收并处理完整的响应;可以提交新的用户消息。
  • error: API 请求期间发生错误,导致未能成功完成。

用户

使用 user prop 来更改 ChatMessage 组件用于 user 消息的 props。默认为

  • side: 'right'
  • variant: 'soft'
你好,你怎么样?
我很好,谢谢你的询问!今天我能如何帮助你?
东京目前的天气如何?
根据最新数据,东京目前天气晴朗,气温在 24°C (75°F) 左右。这是一个晴空万里的好天气。
<script setup lang="ts">
const messages = ref([
  {
    id: '6045235a-a435-46b8-989d-2df38ca2eb47',
    role: 'user',
    content: 'Hello, how are you?'
  },
  {
    id: '7a92b3c1-d5f8-4e76-b8a9-3c1e5fb2e0d8',
    role: 'assistant',
    content: 'I am doing well, thank you for asking! How can I assist you today?'
  },
  {
    id: '9c84d6a7-8b23-4f12-a1d5-e7f3b9c05e2a',
    role: 'user',
    content: 'What is the current weather in Tokyo?'
  },
  {
    id: 'b2e5f8c3-a1d9-4e67-b3f2-c9d8e7a6b5f4',
    role: 'assistant',
    content:
      "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 来更改 ChatMessage 组件用于 assistant 消息的 props。默认为

  • side: 'left'
  • variant: 'naked'
你好,你怎么样?
我很好,谢谢你的询问!今天我能如何帮助你?
东京目前的天气如何?
根据最新数据,东京目前天气晴朗,气温在 24°C (75°F) 左右。这是一个晴空万里的好天气。
<script setup lang="ts">
const messages = ref([
  {
    id: '6045235a-a435-46b8-989d-2df38ca2eb47',
    role: 'user',
    content: 'Hello, how are you?'
  },
  {
    id: '7a92b3c1-d5f8-4e76-b8a9-3c1e5fb2e0d8',
    role: 'assistant',
    content: 'I am doing well, thank you for asking! How can I assist you today?'
  },
  {
    id: '9c84d6a7-8b23-4f12-a1d5-e7f3b9c05e2a',
    role: 'user',
    content: 'What is the current weather in Tokyo?'
  },
  {
    id: 'b2e5f8c3-a1d9-4e67-b3f2-c9d8e7a6b5f4',
    role: 'assistant',
    content:
      "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,Golden Pavilion),其令人惊叹的金箔外观倒映在镜湖中;伏见稻荷大社(Fushimi Inari Shrine),其数千座朱红色鸟居蜿蜒向上穿过山坡;岚山竹林(Arashiyama Bamboo Grove),高耸的竹竿营造出超凡脱俗的氛围;以及坐落在山坡上、可以俯瞰城市全景的清水寺(Kiyomizu-dera Temple);还有历史悠久的祇园区(Gion),在那里你可能会在两旁是传统木制町屋的狭窄石板街上看到艺妓匆匆赶往晚间约会。
<script setup lang="ts">
const messages = ref([
  {
    id: '6045235a-a435-46b8-989d-2df38ca2eb47',
    role: 'user',
    content: 'Hello, how are you?'
  },
  {
    id: '7a92b3c1-d5f8-4e76-b8a9-3c1e5fb2e0d8',
    role: 'assistant',
    content: 'I am doing well, thank you for asking! How can I assist you today?'
  },
  {
    id: '9c84d6a7-8b23-4f12-a1d5-e7f3b9c05e2a',
    role: 'user',
    content: 'What is the current weather in Tokyo?'
  },
  {
    id: 'b2e5f8c3-a1d9-4e67-b3f2-c9d8e7a6b5f4',
    role: 'assistant',
    content:
      "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',
    content: 'Can you recommend some popular tourist attractions in Kyoto?'
  },
  {
    id: 'd4f5g8c3-a1d9-4e67-b3f2-c9d8e7a6b5f4',
    role: 'assistant',
    content:
      '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,Golden Pavilion),其令人惊叹的金箔外观倒映在镜湖中;伏见稻荷大社(Fushimi Inari Shrine),其数千座朱红色鸟居蜿蜒向上穿过山坡;岚山竹林(Arashiyama Bamboo Grove),高耸的竹竿营造出超凡脱俗的氛围;以及坐落在山坡上、可以俯瞰城市全景的清水寺(Kiyomizu-dera Temple);还有历史悠久的祇园区(Gion),在那里你可能会在两旁是传统木制町屋的狭窄石板街上看到艺妓匆匆赶往晚间约会。
<script setup lang="ts">
const messages = ref([
  {
    id: '6045235a-a435-46b8-989d-2df38ca2eb47',
    role: 'user',
    content: 'Hello, how are you?'
  },
  {
    id: '7a92b3c1-d5f8-4e76-b8a9-3c1e5fb2e0d8',
    role: 'assistant',
    content: 'I am doing well, thank you for asking! How can I assist you today?'
  },
  {
    id: '9c84d6a7-8b23-4f12-a1d5-e7f3b9c05e2a',
    role: 'user',
    content: 'What is the current weather in Tokyo?'
  },
  {
    id: 'b2e5f8c3-a1d9-4e67-b3f2-c9d8e7a6b5f4',
    role: 'assistant',
    content:
      "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',
    content: 'Can you recommend some popular tourist attractions in Kyoto?'
  },
  {
    id: 'd4f5g8c3-a1d9-4e67-b3f2-c9d8e7a6b5f4',
    role: 'assistant',
    content:
      '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 SDKuseChat 可组合函数一起使用。
查看 GitHub 上我们的 AI Chat template 源代码,获取实际示例。

在页面中使用

将 ChatMessages 组件与 useChat 可组合函数一起使用,以在页面内显示聊天消息列表。

传递 messages prop 以及将用于自动滚动和指示器显示的 status prop。

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

const { messages, input, handleSubmit, reload, stop, status, error } = useChat()
</script>

<template>
  <UDashboardPanel>
    <template #body>
      <UContainer>
        <UChatMessages :messages="messages" :status="status">
          <template #content="{ message }">
            <MDC :value="message.content" :cache-key="message.id" unwrap="p" />
          </template>
        </UChatMessages>
      </UContainer>
    </template>

    <template #footer>
      <UContainer>
        <UChatPrompt v-model="input" :error="error" @submit="handleSubmit">
          <UChatPromptSubmit :status="status" @stop="stop" @reload="reload" />
        </UChatPrompt>
      </UContainer>
    </template>
  </UDashboardPanel>
</template>
在此示例中,我们使用来自@nuxtjs/mdcMDC 组件来渲染消息内容。由于 Nuxt UI Pro 提供了预设样式的排版(prose)组件,你的内容将自动获得样式。

API

Props

Prop默认值类型
autoScroll

true

boolean | Partial<ButtonProps>

shouldAutoScroll

false

boolean

shouldScrollToBottom

true

boolean

spacingOffset

0

number

messages

Message[]

user

Pick<ChatMessageProps, "icon" | "variant" | "avatar" | "side" | "actions">

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

compact

false

boolean

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

assistant

Pick<ChatMessageProps, "icon" | "variant" | "avatar" | "side" | "actions">

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

status

"error" | "submitted" | "streaming" | "ready"

autoScrollIcon

appConfig.ui.icons.arrowDown

string

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

ui

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

插槽 (Slots)

插槽 (Slot)类型
default

{}

indicator

{}

viewport

{ onClick: () => void; }

content

{ message: Message; }

leading

{ message: Message; }

actions

{ message: Message; }

你可以在 ChatMessages 组件内部使用 ChatMessage 组件的所有插槽,它们会自动转发,允许你在使用 messages prop 时自定义单条消息。
<template>
  <UChatMessages :messages="messages" :status="status">
    <template #content="{ message }">
      <MDC :value="message.content" :cache-key="message.id" unwrap="p" />
    </template>
  </UChatMessages>
</template>

主题

app.config.ts
export default defineAppConfig({
  uiPro: {
    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({
      uiPro: {
        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 uiPro from '@nuxt/ui-pro/vite'

export default defineConfig({
  plugins: [
    vue(),
    uiPro({
      uiPro: {
        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: ''
            }
          }
        }
      }
    })
  ]
})