npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ai-chat-waterfall

v1.0.1

Published

专为AI聊天界面设计的瀑布流核心逻辑包,跨框架兼容、流式渲染、无样式耦合

Readme

ai-chat-waterfall

专为 AI 聊天界面设计的瀑布流核心逻辑包,跨框架兼容、流式渲染、无样式耦合

npm version license TypeScript

✨ 核心特性

  • 🎯 逻辑与样式完全解耦:仅输出布局数值/渲染时机控制,样式由开发者完全自定义
  • 🔄 跨框架通用:基于原生 JS 封装核心逻辑,支持 React/Vue3/原生 JS/其他框架
  • 🤖 AI 场景深度适配:支持打字机式流式渲染、按块追加、动态高度计算、自动滚动
  • 🚀 生产级健壮性:包含错误处理、内存泄漏防护、大数据量性能优化(虚拟列表)
  • 🎨 完整组件生态:提供 ProChat、ChatList、MessageInput 等开箱即用组件
  • 🎭 对标 pro-chat:API 设计对标 @ant-design/pro-chat,支持流式推送、消息管理等
  • 📦 体积小巧:核心逻辑仅 2.5KB (gzip),React 适配层 5.4KB,Vue 适配层 5.9KB
  • 🎨 样式系统:提供默认样式和 CSS 变量,支持主题定制

📦 安装

npm install ai-chat-waterfall

# 可选:安装 marked 以获得完整的 Markdown 支持
npm install marked

💡 提示:如果不安装 marked,包会使用内置的简单 Markdown 渲染器。安装 marked 后会自动使用,获得更完整的 Markdown 支持(表格、任务列表、GFM 等)。

🚀 快速开始

方式一:React 接入(推荐)

使用 ProChat 组件(完整功能)

import { ProChat } from 'ai-chat-waterfall/react';
import 'ai-chat-waterfall/dist/styles/index.css'; // 引入默认样式

function App() {
  const chatRef = useRef();

  const handleSend = async (content) => {
    // 发送用户消息后,处理 AI 回复
    const messageId = chatRef.current?.sendMessage(content, 'user');
    
    // 模拟 API 调用
    const response = await fetch('/api/chat', {
      method: 'POST',
      body: JSON.stringify({ message: content })
    });
    
    // 流式推送 AI 回复
    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let aiMessageId = '';
    
    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      
      const chunk = decoder.decode(value);
      if (!aiMessageId) {
        // 创建 AI 消息
        chatRef.current?.pushChat({
          content: chunk,
          role: 'assistant'
        });
        aiMessageId = chatRef.current?.getChatLoadingId();
      } else {
        // 追加内容
        chatRef.current?.pushChat({
          id: aiMessageId,
          content: chunk,
          role: 'assistant'
        });
      }
    }
  };

  return (
    <div style={{ height: '600px' }}>
      <ProChat
        ref={chatRef}
        initialMessages={[]}
        onMessageSend={handleSend}
        renderMessage={(msg) => (
          <div style={{ 
            padding: '12px', 
            background: msg.role === 'user' ? '#e3f2fd' : '#f5f5f5',
            borderRadius: '8px'
          }}>
            {msg.content}
          </div>
        )}
      />
    </div>
  );
}

使用独立组件

import { ChatList, MessageInput } from 'ai-chat-waterfall/react';
import { useState } from 'react';

function CustomChat() {
  const [messages, setMessages] = useState([]);
  const [loadingId, setLoadingId] = useState(null);

  const handleSend = async (text) => {
    // 添加用户消息
    const userMsg = {
      id: `user-${Date.now()}`,
      role: 'user',
      content: text,
      createAt: Date.now(),
      updateAt: Date.now()
    };
    setMessages(prev => [...prev, userMsg]);

    // 添加 AI 消息(流式)
    const aiMsgId = `ai-${Date.now()}`;
    setMessages(prev => [...prev, {
      id: aiMsgId,
      role: 'assistant',
      content: '',
      isStreaming: true,
      createAt: Date.now(),
      updateAt: Date.now()
    }]);
    setLoadingId(aiMsgId);

    // 模拟流式响应
    // ... 处理流式数据
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '600px' }}>
      <ChatList 
        data={messages} 
        loadingId={loadingId}
        renderMessage={(msg) => <div>{msg.content}</div>}
      />
      <MessageInput 
        onConfirm={handleSend}
        placeholder="输入消息..."
      />
    </div>
  );
}

方式二:Vue 3 接入(推荐)

使用 ProChat 组件

<template>
  <div style="height: 600px">
    <ProChat
      ref="chatRef"
      :initial-messages="[]"
      @message-send="handleSend"
      @messages-change="handleMessagesChange"
    />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { ProChat } from 'ai-chat-waterfall/vue';
import 'ai-chat-waterfall/dist/styles/index.css';

const chatRef = ref();

const handleSend = async (content: string) => {
  // 发送用户消息
  chatRef.value?.sendMessage(content, 'user');
  
  // 模拟流式推送
  const chunks = ['这是', '一段', '流式', '回复内容。'];
  for (const chunk of chunks) {
    await new Promise(resolve => setTimeout(resolve, 100));
    chatRef.value?.pushChat({
      id: 'ai-response',
      content: chunk,
      role: 'assistant'
    });
  }
};

const handleMessagesChange = (messages: ChatMessage[]) => {
  console.log('消息更新:', messages);
};
</script>

使用独立组件

<template>
  <div style="display: flex; flex-direction: column; height: 600px">
    <ChatList 
      :data="messages" 
      :loading-id="loadingId"
    />
    <MessageInput 
      v-model="inputText"
      @confirm="handleSend"
      placeholder="输入消息..."
    />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { ChatList, MessageInput } from 'ai-chat-waterfall/vue';
import type { ChatMessage } from 'ai-chat-waterfall';

const messages = ref<ChatMessage[]>([]);
const loadingId = ref<string | undefined>();
const inputText = ref('');

const handleSend = (text: string) => {
  // 处理发送逻辑
  messages.value.push({
    id: `user-${Date.now()}`,
    role: 'user',
    content: text,
    createAt: Date.now(),
    updateAt: Date.now()
  });
  inputText.value = '';
};
</script>

方式三:原生 JavaScript 接入

基础使用

<!DOCTYPE html>
<html>
<head>
  <title>AI Chat Waterfall Demo</title>
</head>
<body>
  <div id="chat-container" style="width: 100%; height: 500px; overflow-y: auto; display: flex; flex-direction: column; padding: 16px;"></div>
  
  <script src="https://unpkg.com/ai-chat-waterfall/dist/ai-chat-waterfall.umd.js"></script>
  <script>
    const container = document.getElementById('chat-container');
    const waterfall = new AIChatWaterfall(container, {
      typewriterSpeed: 50,
      autoScroll: true,
      autoDetectHtml: true
    });

    // 添加用户消息
    function addUserMessage(content) {
      const messageEl = document.createElement('div');
      messageEl.dataset.msgId = `user-${Date.now()}`;
      messageEl.dataset.msgRole = 'user';
      
      const layout = waterfall.calculateBubbleLayout(messageEl, 'user');
      Object.assign(messageEl.style, {
        ...layout,
        background: '#e3f2fd',
        padding: '12px',
        borderRadius: '8px',
        marginBottom: layout.marginBottom
      });
      
      messageEl.textContent = content;
      container.appendChild(messageEl);
    }

    // 添加 AI 消息(流式渲染)
    function addAIMessage(content) {
      const messageId = `ai-${Date.now()}`;
      const messageEl = document.createElement('div');
      messageEl.dataset.msgId = messageId;
      messageEl.dataset.msgRole = 'ai';
      
      const layout = waterfall.calculateBubbleLayout(messageEl, 'ai');
      Object.assign(messageEl.style, {
        ...layout,
        background: '#f5f5f5',
        padding: '12px',
        borderRadius: '8px',
        marginBottom: layout.marginBottom
      });
      
      const contentEl = document.createElement('div');
      messageEl.appendChild(contentEl);
      container.appendChild(messageEl);
      
      // 启动流式渲染
      waterfall.streamRenderContent(messageId, contentEl, content);
    }

    // 使用示例
    addUserMessage('你好!');
    setTimeout(() => {
      addAIMessage('你好!有什么可以帮助你的吗?');
    }, 500);
  </script>
</body>
</html>

按块追加(适用于 SSE/WebSocket)

// 当 API 返回的是段落块时,使用 appendChunk
const contentEl = document.querySelector('#ai-message-content');
const messageId = 'ai-1';

// 模拟 SSE 事件流
const eventSource = new EventSource('/api/stream');
eventSource.onmessage = (event) => {
  const chunk = event.data;
  waterfall.appendChunk(messageId, contentEl, chunk);
};

eventSource.onclose = () => {
  waterfall.finishChunkAppend(messageId);
};

瀑布流布局(多列布局)

// 启用瀑布流布局
const waterfall = new AIChatWaterfall(container, {
  waterfallLayout: true,      // 启用瀑布流
  waterfallColumns: 2,         // 2列布局
  waterfallColumnGap: 16,     // 列间距16px
  gap: 12                      // 消息间距
});

// 创建消息时,布局会自动分配到最短的列
const layout = waterfall.calculateBubbleLayout(bubbleEl, 'ai');
// layout.columnIndex 会返回分配的列索引(0 或 1)
// layout.columnWidth 会返回列宽度

// 应用样式
bubbleEl.style.width = layout.columnWidth;
bubbleEl.style.position = 'absolute';
bubbleEl.style.left = `${layout.columnIndex * (parseInt(layout.columnWidth) + 16)}px`;

📖 API 文档

核心类:AIChatWaterfall

构造函数

new AIChatWaterfall(container: HTMLElement, options?: AIChatWaterfallOptions)

参数:

  • container: 容器 DOM 节点(必须)
  • options: 配置选项(可选)

配置选项

interface AIChatWaterfallOptions {
  // 基础配置
  gap?: number;                    // 消息项间距(px),默认 12
  typewriterSpeed?: number;        // 打字机速度(ms/字),0 关闭逐字渲染,默认 50
  autoScroll?: boolean;            // 是否自动滚动到底部,默认 true
  autoDetectHtml?: boolean;        // 是否自动检测并渲染 HTML/Markdown,默认 true
  
  // 虚拟列表配置
  virtualScroll?: boolean;         // 是否开启虚拟列表,默认 false
  virtualItemHeight?: number;       // 虚拟列表默认占位高度(px),默认 60
  
  // 瀑布流布局配置
  waterfallLayout?: boolean;       // 是否启用瀑布流布局(多列布局),默认 false
  waterfallColumns?: number;       // 瀑布流列数,默认 2(仅在 waterfallLayout=true 时生效)
  waterfallColumnGap?: number;     // 瀑布流列间距(px),默认 16
  
  // Markdown 配置
  markdownRenderer?: (content: string) => string; // 自定义 Markdown 渲染器
  
  // 回调函数
  onStreamStart?: (streamId: string) => void;     // 流式渲染开始回调
  onStreamEnd?: (streamId: string) => void;       // 流式渲染结束回调
  onChunkAppended?: (streamId: string, chunk: string, totalContent: string) => void; // 块追加回调
  onError?: (error: Error) => void;               // 错误回调
  onVirtualRangeChange?: (range: [number, number]) => void; // 虚拟列表可视区域变化回调
}

核心方法

calculateBubbleLayout

计算单个聊天气泡的布局数值。

calculateBubbleLayout(bubbleEl: HTMLElement | null, role: 'user' | 'ai'): BubbleLayout

返回:

interface BubbleLayout {
  maxWidth: string;              // 最大宽度(70% 容器宽度,瀑布流模式下为列宽度)
  alignSelf: 'flex-start' | 'flex-end'; // 对齐方式
  marginBottom: string;          // 底部间距
  height?: string;               // 高度(如果传入了 DOM 节点)
  columnIndex?: number;          // 瀑布流布局中的列索引(0-based)
  columnWidth?: string;         // 瀑布流布局中的列宽度
}

示例:

const layout = waterfall.calculateBubbleLayout(bubbleEl, 'user');
// 只应用必要的样式,保留 CSS 类的 align-self
bubbleEl.style.maxWidth = layout.maxWidth;
bubbleEl.style.marginBottom = layout.marginBottom;
streamRenderContent

AI 消息流式渲染(打字机效果)。

streamRenderContent(streamId: string, contentEl: HTMLElement, fullContent: string): Promise<void>

参数:

  • streamId: 流式渲染唯一ID(建议用消息ID)
  • contentEl: 消息内容 DOM 节点
  • fullContent: 完整 AI 回复内容

示例:

await waterfall.streamRenderContent('ai-1', contentEl, '这是完整的 AI 回复内容...');
appendChunk

按块追加内容(适用于 API 一段一段返回的场景)。

appendChunk(streamId: string, contentEl: HTMLElement, chunk: string): Promise<void>

使用场景:

  • SSE (Server-Sent Events) 流式响应
  • WebSocket 实时推送
  • 分块 API 响应

示例:

// SSE 示例
const eventSource = new EventSource('/api/stream');
eventSource.onmessage = (event) => {
  waterfall.appendChunk('ai-1', contentEl, event.data);
};
eventSource.onclose = () => {
  waterfall.finishChunkAppend('ai-1');
};
finishChunkAppend

完成块追加,标记流式渲染结束。

finishChunkAppend(streamId: string): void
pauseStream / resumeStream / stopStream

控制流式渲染的暂停、恢复和停止。

pauseStream(streamId?: string): void
resumeStream(streamId: string, contentEl: HTMLElement, fullContent: string, resumeIndex?: number): void
stopStream(streamId: string): void
autoScrollToBottom

自动滚动到底部。

autoScrollToBottom(force?: boolean): void
getMessageState

获取消息当前渲染状态。

getMessageState(msgId: string): AIChatMessageState | null

返回:

interface AIChatMessageState {
  realHeight?: number;      // 消息气泡真实高度
  isStreaming?: boolean;    // 是否正在流式渲染
  streamProgress?: number; // 流式渲染进度(0-1)
}
destroy

销毁实例,清理所有状态/事件/定时器。

destroy(): void

ChatStore:消息状态管理

消息状态管理核心类,提供完整的消息 CRUD 操作。

import { ChatStore } from 'ai-chat-waterfall';

const store = new ChatStore({
  initialMessages: [],
  onMessagesChange: (messages) => {
    console.log('消息更新:', messages);
  }
});

// 发送消息
const messageId = store.sendMessage('你好', 'user');

// 推送流式消息
store.pushChat({
  id: 'ai-1',
  content: 'AI 回复...',
  role: 'assistant'
});

// 获取所有消息
const messages = store.getChats();

// 更新消息
store.setMessageContent('ai-1', '更新后的内容');

// 删除消息
store.deleteMessage('ai-1');

// 清空所有消息
store.clearMessage();

ProChat 组件(对标 @ant-design/pro-chat)

完整的聊天组件,包含消息列表和输入框。

React 版本

import { ProChat, ProChatRef } from 'ai-chat-waterfall/react';

interface ProChatProps {
  initialMessages?: ChatMessage[];                    // 初始消息列表
  messages?: ChatMessage[];                           // 受控模式的消息列表
  controlled?: boolean;                               // 是否受控模式
  onMessageSend?: (content: string, role?: string) => void | Promise<void>; // 发送消息回调
  onMessagesChange?: (messages: ChatMessage[]) => void; // 消息变化回调
  inputAreaRender?: (defaultDom: ReactNode, onMessageSend: (content: string) => void) => ReactNode; // 自定义输入区域
  inputRender?: (defaultDom: ReactNode, onMessageSend: (content: string) => void) => ReactNode; // 自定义输入框
  renderMessage?: (message: ChatMessage) => ReactNode; // 自定义消息渲染
  renderErrorMessage?: (message: ChatMessage) => ReactNode; // 自定义错误消息渲染
  renderItem?: (message: ChatMessage, index: number) => ReactNode; // 自定义消息项渲染
  style?: CSSProperties;                              // 样式
  className?: string;                                 // 类名
  waterfallOptions?: AIChatWaterfallOptions;          // 核心配置选项
}

Vue 版本

import { ProChat } from 'ai-chat-waterfall/vue';

interface ProChatProps {
  initialMessages?: ChatMessage[];
  messages?: ChatMessage[];
  controlled?: boolean;
  onMessageSend?: (content: string, role?: string) => void | Promise<void>;
  onMessagesChange?: (messages: ChatMessage[]) => void;
  // ... 其他属性同 React 版本
}

实例方法(通过 ref 访问)

interface ProChatRef {
  // 消息查询
  getChats: () => ChatMessage[];                     // 获取所有消息
  getChatById: (id: string) => ChatMessage | undefined; // 根据ID获取消息
  getChatLoadingId: () => string | undefined;         // 获取正在加载的消息ID
  
  // 消息操作
  sendMessage: (content: string, role?: AIChatMessageRole) => string; // 发送消息
  pushChat: (chat: Partial<ChatMessage> & { content: string; role: string }) => void; // 推送新消息(流式)
  setChat: (id: string, chat: Partial<ChatMessage>) => void; // 设置/更新消息
  setMessageContent: (id: string, content: string) => void; // 设置消息内容
  setMessageValue: <K extends keyof ChatMessage>(id: string, key: K, value: ChatMessage[K]) => void; // 设置消息属性
  
  // 消息控制
  resendMessage: (id: string) => void;               // 重试消息
  stopGenerateMessage: () => void;                    // 停止生成
  deleteMessage: (id: string) => void;                // 删除消息
  clearMessage: () => void;                           // 清空所有消息
  
  // 视图控制
  scrollToBottom: () => void;                         // 滚动到底部
  
  // 实例访问
  getWaterfallInstance: () => AIChatWaterfall | null; // 获取核心实例
  getStoreInstance: () => ChatStore | null;           // 获取 Store 实例
}

ChatList 组件

独立的聊天列表组件,用于显示消息列表。

React 版本

import { ChatList } from 'ai-chat-waterfall/react';

interface ChatListProps {
  data: ChatMessage[];                                // 消息数据
  loadingId?: string;                                 // 正在加载的消息ID
  showTitle?: boolean;                                 // 是否显示标题
  renderMessage?: (message: ChatMessage) => ReactNode; // 自定义消息渲染
  renderErrorMessage?: (message: ChatMessage) => ReactNode; // 自定义错误消息渲染
  renderItem?: (message: ChatMessage, index: number) => ReactNode; // 自定义消息项渲染
  renderActions?: (message: ChatMessage) => ReactNode; // 自定义操作按钮渲染
  onMessageChange?: (id: string, content: string) => void; // 消息内容变化回调
  onActionClick?: (action: string, message: ChatMessage) => void; // 操作按钮点击回调
  style?: CSSProperties;                              // 样式
  className?: string;                                 // 类名
  waterfallOptions?: AIChatWaterfallOptions;          // 核心配置选项
}

Vue 版本

import { ChatList } from 'ai-chat-waterfall/vue';

// Props 同 React 版本,使用 Vue 的 props 定义方式

MessageInput 组件

独立的输入框组件,用于输入聊天消息。

React 版本

import { MessageInput } from 'ai-chat-waterfall/react';

interface MessageInputProps {
  defaultValue?: string;                              // 默认值
  value?: string;                                     // 受控值
  onChange?: (value: string) => void;                // 值变化回调
  onConfirm?: (text: string) => void;                // 确认回调(点击发送或按 Enter)
  onCancel?: () => void;                              // 取消回调
  height?: number | 'auto' | string;                 // 高度
  placeholder?: string;                               // 占位符
  disabled?: boolean;                                 // 是否禁用
  renderButtons?: (text: string) => ReactNode;       // 自定义按钮渲染
  text?: { cancel?: string; confirm?: string };      // 按钮文本配置
  style?: CSSProperties;                             // 样式
  className?: string;                                 // 类名
  textareaClassName?: string;                        // 文本域类名
  textareaStyle?: CSSProperties;                     // 文本域样式
}

Vue 版本

import { MessageInput } from 'ai-chat-waterfall/vue';

// 使用 v-model 绑定值
<MessageInput 
  v-model="inputText"
  @confirm="handleSend"
  placeholder="输入消息..."
/>

🎨 样式系统

引入默认样式

// React/Vue 项目
import 'ai-chat-waterfall/dist/styles/index.css';

CSS 变量定制

所有样式都使用 CSS 变量,可以通过覆盖变量来定制主题:

:root {
  /* 颜色变量 */
  --ai-chat-primary-color: #1890ff;
  --ai-chat-primary-hover: #40a9ff;
  --ai-chat-primary-active: #096dd9;
  --ai-chat-text-color: #333;
  --ai-chat-text-secondary: #999;
  --ai-chat-border-color: #e0e0e0;
  --ai-chat-background: #fff;
  --ai-chat-user-bubble-bg: #e3f2fd;
  --ai-chat-ai-bubble-bg: #f5f5f5;
  --ai-chat-error-color: #ff4d4f;

  /* 间距变量 */
  --ai-chat-gap: 12px;
  --ai-chat-padding: 16px;
  --ai-chat-padding-small: 8px;

  /* 圆角变量 */
  --ai-chat-border-radius: 8px;
  --ai-chat-border-radius-small: 4px;

  /* 字体变量 */
  --ai-chat-font-size: 14px;
  --ai-chat-font-size-small: 12px;
  --ai-chat-line-height: 1.5;

  /* 阴影变量 */
  --ai-chat-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

自定义样式

所有组件都支持通过 classNamestyle 属性自定义样式:

<ProChat
  className="my-custom-chat"
  style={{ height: '600px' }}
  renderMessage={(msg) => (
    <div className="my-custom-message">
      {msg.content}
    </div>
  )}
/>

💡 使用场景

场景一:OpenAI API 流式响应

// 使用 fetch 处理流式响应
const response = await fetch('/api/openai', {
  method: 'POST',
  body: JSON.stringify({ message: userMessage })
});

const reader = response.body.getReader();
const decoder = new TextDecoder();
let fullContent = '';

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  
  const chunk = decoder.decode(value);
  fullContent += chunk;
  
  // 使用 appendChunk 实时更新
  await waterfall.appendChunk('ai-1', contentEl, chunk);
}

waterfall.finishChunkAppend('ai-1');

场景二:WebSocket 实时聊天

const ws = new WebSocket('wss://api.example.com/chat');

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  
  if (data.type === 'chunk') {
    // 流式追加
    waterfall.appendChunk(data.messageId, contentEl, data.content);
  } else if (data.type === 'done') {
    // 完成
    waterfall.finishChunkAppend(data.messageId);
  }
};

场景三:SSE (Server-Sent Events)

const eventSource = new EventSource('/api/stream');

eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data);
  waterfall.appendChunk(data.messageId, contentEl, data.chunk);
};

eventSource.addEventListener('done', (event) => {
  const data = JSON.parse(event.data);
  waterfall.finishChunkAppend(data.messageId);
  eventSource.close();
});

🔧 最佳实践

1. 消息 ID 管理

// ✅ 推荐:使用唯一且可预测的 ID
const messageId = `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;

// ❌ 不推荐:使用简单的递增数字
let messageId = 1; // 可能导致 ID 冲突

2. 流式渲染性能优化

// ✅ 推荐:使用 appendChunk 处理大块内容
for (const chunk of largeChunks) {
  await waterfall.appendChunk(messageId, contentEl, chunk);
}

// ❌ 不推荐:逐字渲染超长内容
await waterfall.streamRenderContent(messageId, contentEl, veryLongContent); // 可能很慢

3. 内存管理

// ✅ 推荐:组件卸载时销毁实例
useEffect(() => {
  const waterfall = new AIChatWaterfall(container, options);
  return () => {
    waterfall.destroy(); // 清理资源
  };
}, []);

4. 错误处理

const waterfall = new AIChatWaterfall(container, {
  onError: (error) => {
    // 统一错误处理
    console.error('Chat error:', error);
    // 可以发送到错误监控服务
  }
});

📊 性能优化

虚拟列表

对于大量消息(> 100 条),建议开启虚拟列表:

const waterfall = new AIChatWaterfall(container, {
  virtualScroll: true,
  virtualItemHeight: 80, // 根据实际消息高度调整
  onVirtualRangeChange: (range) => {
    // 只渲染可视区域的消息
    console.log('可视区域:', range);
  }
});

流式渲染优化

// 对于快速到达的流式数据,可以批量处理
let buffer = '';
const flushBuffer = () => {
  if (buffer) {
    waterfall.appendChunk(messageId, contentEl, buffer);
    buffer = '';
  }
};

// 每 100ms 刷新一次
setInterval(flushBuffer, 100);

🆚 与 @ant-design/pro-chat 对比

| 特性 | ai-chat-waterfall | @ant-design/pro-chat | |------|-------------------|---------------------| | 框架支持 | React + Vue + 原生 JS | 仅 React | | 样式耦合 | 完全解耦 | 依赖 Ant Design | | 体积 | 核心 2.5KB (gzip) | 较大(包含 Ant Design) | | 自定义能力 | 完全自定义 | 有限的自定义 | | 学习成本 | 低(API 简单) | 中等(需要了解 Ant Design) | | 适用场景 | 所有框架项目 | React + Ant Design 项目 |

🔧 开发

# 安装依赖
npm install

# 开发构建(包含 source map)
npm run build:dev

# 生产构建(无 source map,体积更小)
npm run build

# 类型检查
npm run type-check

📝 版本历史

v1.0.0 (当前版本)

  • ✅ 核心逻辑(布局计算 + 流式渲染 + 自动滚动)
  • ✅ React 适配层(ProChat、ChatList、MessageInput)
  • ✅ Vue 3 适配层(ProChat、ChatList、MessageInput)
  • ✅ 消息状态管理(ChatStore)
  • ✅ 按块追加支持(appendChunk)
  • ✅ 瀑布流布局支持
  • ✅ 默认样式系统
  • ✅ 虚拟列表支持

计划中的功能

  • 🔄 消息折叠/展开
  • 🔄 多语言适配
  • 🔄 更多 UI 组件(工具栏、操作按钮等)
  • 🔄 消息搜索功能
  • 🔄 消息导出功能

🤝 贡献

欢迎提交 Issue 和 Pull Request!

📄 许可证

MIT


Made with ❤️ for AI Chat Applications

GitHub · Issues · NPM