0.1.1 • Published 4 months ago

@aiwanna-team/message-list v0.1.1

Weekly downloads
-
License
-
Repository
-
Last release
4 months ago

@aiwanna-team/message-list

一个基于 React + TypeScript + Virtuoso 的高性能消息列表组件,专为聊天应用和实时通讯场景设计。

✨ 功能特性

  • 🚀 高性能虚拟滚动 - 基于 Virtuoso 引擎,支持大量消息流畅渲染
  • 💬 智能消息气泡 - 自动分组显示,支持连续消息的视觉优化
  • 📱 响应式设计 - 完美适配移动端和桌面端
  • 时间戳显示 - 自动格式化消息时间
  • 🔄 上拉加载历史 - 支持异步加载历史消息,游标分页
  • 🎨 自定义样式 - 基于 TailwindCSS,易于定制
  • 📝 消息更新 - 支持实时更新消息内容(AI 流式回复场景)
  • 🔧 TypeScript 支持 - 完整的类型定义

📦 安装

npm install @aiwanna-team/message-list

依赖要求

确保你的项目已安装以下依赖:

npm install react react-dom tailwindcss @tailwindcss/vite

最低版本要求:

  • Node.js >= 20.0.0
  • React >= 19.1.0
  • TailwindCSS >= 4.1.8

🚀 快速开始

设置步骤

  1. 安装组件库

    npm install @aiwanna-team/message-list
  2. 配置 TailwindCSS 源文件检测

    在你的主 CSS 文件(如 src/app.css)中添加:

    @import "tailwindcss";
    @source "../node_modules/@aiwanna-team/message-list";
  3. 开始使用组件

基础使用

import React, { useRef } from 'react'
import MessageList, { 
  type MessageListMethods, 
  type Message 
} from '@aiwanna-team/message-list'
import '@aiwanna-team/message-list/css'

function ChatApp() {
  const messageListRef = useRef<MessageListMethods>(null)

  const initialMessages: Message[] = [
    {
      key: 'msg-1',
      text: '你好!欢迎使用消息列表组件',
      user: 'other',
      timestamp: new Date(),
    },
    {
      key: 'msg-2',
      text: '这个组件很棒!',
      user: 'me',
      timestamp: new Date(),
    }
  ]

  const handleSendMessage = () => {
    messageListRef.current?.sendMessage('新消息内容')
  }

  return (
    <div className="w-full max-w-2xl mx-auto">
      <MessageList
        ref={messageListRef}
        height="500px"
        initialMessages={initialMessages}
      />
      <button 
        onClick={handleSendMessage}
        className="mt-4 px-4 py-2 bg-blue-500 text-white rounded"
      >
        发送消息
      </button>
    </div>
  )
}

配置 TailwindCSS

⚠️ 重要配置:由于该组件使用了 TailwindCSS 样式,你需要在项目的 CSS 文件中注册组件库的源文件,否则 TailwindCSS 无法检测到组件中使用的类名,导致样式缺失。

在你的主 CSS 文件中添加:

@import "tailwindcss";
@source "../node_modules/@aiwanna-team/message-list";

这样 TailwindCSS 就能扫描组件库中的样式类并生成对应的 CSS。

示例项目结构:

your-project/
├── src/
│   ├── app.css          # 在这里添加 @source 指令
│   └── main.tsx
└── node_modules/
    └── @aiwanna-team/
        └── message-list/

了解更多关于源文件检测的信息,请参考 TailwindCSS 官方文档

📚 API 文档

MessageList 组件属性

属性类型默认值说明
heightstring \| number"500px"消息列表容器高度
classNamestring""自定义 CSS 类名
styleReact.CSSProperties-自定义样式
initialMessagesMessage[][]初始消息列表
onLoadHistoryLoadHistoryFunction-历史消息加载回调
historyLoadLimitnumber20每次加载历史消息数量
loadThresholdnumber100触发加载的滚动阈值(px)
autoHideScrollbarbooleantrue是否自动隐藏滚动条
licenseKeystring""Virtuoso 许可证密钥

MessageListMethods 实例方法

interface MessageListMethods {
  /** 发送消息,返回消息key */
  sendMessage: (text: string) => string
  /** 接收消息,返回消息key */
  receiveMessage: (text: string) => string
  /** 更新消息内容 */
  updateMessage: (key: string, newText: string) => void
  /** 获取所有消息 */
  getAllMessages: () => Message[]
  /** 清空消息列表 */
  clearMessages: () => void
  /** 重设消息列表 */
  resetMessages: (messages: Message[]) => void
}

Message 数据结构

interface Message {
  /** 消息唯一标识 */
  key: string
  /** 消息文本内容 */
  text: string
  /** 消息发送者 */
  user: "me" | "other"
  /** 消息时间戳 */
  timestamp?: Date
}

LoadHistoryFunction 回调类型

type LoadHistoryFunction = (
  beforeMessageKey?: string,
  limit?: number
) => Promise<Message[]>

🔄 历史消息加载

基础配置

import { useCallback } from 'react'

function ChatApp() {
  // 历史消息加载函数
  const handleLoadHistory = useCallback(async (beforeMessageKey, limit = 20) => {
    try {
      // 调用你的 API
      const response = await fetch(`/api/messages?before=${beforeMessageKey}&limit=${limit}`)
      const data = await response.json()
      
      // 返回消息数组
      return data.messages.map(msg => ({
        key: msg.id,
        text: msg.content,
        user: msg.sender === 'currentUser' ? 'me' : 'other',
        timestamp: new Date(msg.createdAt),
      }))
    } catch (error) {
      console.error('加载历史消息失败:', error)
      return [] // 返回空数组表示加载完成
    }
  }, [])

  return (
    <MessageList
      onLoadHistory={handleLoadHistory}
      historyLoadLimit={20}
      loadThreshold={100}
    />
  )
}

游标分页说明

  • beforeMessageKey: 游标位置,加载此消息之前的历史记录
  • limit: 每次加载的消息数量
  • 返回空数组 [] 表示没有更多历史消息

🤖 AI 聊天集成

流式回复示例

function AIChatApp() {
  const messageListRef = useRef<MessageListMethods>(null)

  const handleAIChat = async (question: string) => {
    // 发送用户问题
    messageListRef.current?.sendMessage(question)
    
    // 创建 AI 回复占位符
    const botMessageKey = messageListRef.current?.receiveMessage('正在思考...')
    
    try {
      // 模拟流式回复
      const responses = [
        '让我想想...',
        '让我想想...这是一个很好的问题',
        '让我想想...这是一个很好的问题,我来为你详细解答。'
      ]
      
      for (let i = 0; i < responses.length; i++) {
        await new Promise(resolve => setTimeout(resolve, 500))
        messageListRef.current?.updateMessage(botMessageKey!, responses[i])
      }
    } catch (error) {
      messageListRef.current?.updateMessage(botMessageKey!, '抱歉,出现了错误')
    }
  }

  return (
    <div>
      <MessageList ref={messageListRef} />
      <button onClick={() => handleAIChat('你好,你是谁?')}>
        测试 AI 回复
      </button>
    </div>
  )
}

🎨 自定义样式

基础样式定制

<MessageList
  className="border-2 border-blue-200 shadow-lg"
  style={{
    borderRadius: '16px',
    background: 'linear-gradient(to bottom, #f8fafc, #ffffff)'
  }}
/>

高级样式定制(待开发)

通过 CSS 变量覆盖默认样式:

.message-list-container {
  --message-bg-me: #3b82f6;
  --message-bg-other: #f3f4f6;
  --message-text-me: #ffffff;
  --message-text-other: #1f2937;
}

📖 使用示例

聊天室应用

import { useState, useRef, useCallback } from 'react'
import MessageList, { type MessageListMethods, type Message } from '@aiwanna-team/message-list'

function ChatRoom() {
  const [inputValue, setInputValue] = useState('')
  const messageListRef = useRef<MessageListMethods>(null)
  
  const handleSend = () => {
    if (inputValue.trim()) {
      messageListRef.current?.sendMessage(inputValue)
      setInputValue('')
    }
  }
  
  const handleLoadHistory = useCallback(async (beforeKey, limit) => {
    // 实现你的历史消息加载逻辑
    const messages = await loadHistoryFromAPI(beforeKey, limit)
    return messages
  }, [])

  return (
    <div className="flex flex-col h-screen max-w-2xl mx-auto">
      <div className="flex-1 p-4">
        <MessageList
          ref={messageListRef}
          height="100%"
          onLoadHistory={handleLoadHistory}
        />
      </div>
      
      <div className="p-4 border-t flex gap-2">
        <input
          value={inputValue}
          onChange={(e) => setInputValue(e.target.value)}
          onKeyPress={(e) => e.key === 'Enter' && handleSend()}
          className="flex-1 px-3 py-2 border rounded-lg"
          placeholder="输入消息..."
        />
        <button
          onClick={handleSend}
          className="px-4 py-2 bg-blue-500 text-white rounded-lg"
        >
          发送
        </button>
      </div>
    </div>
  )
}

🧪 开发和测试

运行 Storybook

# 克隆仓库
git clone <repository-url>
cd message-list

# 安装依赖
npm install

# 启动 Storybook
npm run storybook

可用的演示

  • Default - 基础使用演示
  • WithInitialMessages - 初始消息展示
  • Interactive - 交互式功能演示
  • HistoryLoading - 历史消息加载演示
  • Performance - 性能压力测试
  • CustomStyle - 自定义样式演示

⚡ 性能优化

最佳实践

  1. 合理设置历史加载数量
<MessageList
  historyLoadLimit={30}  // 根据网络状况调整
  loadThreshold={150}    // 调整触发距离
/>
  1. 使用 useCallback 优化回调
const handleLoadHistory = useCallback(async (beforeKey, limit) => {
  // 实现逻辑
}, [/* 最小依赖 */])
  1. 避免频繁的消息更新
// 批量更新而不是逐条更新
const batchUpdate = (updates) => {
  updates.forEach(({ key, text }) => {
    messageListRef.current?.updateMessage(key, text)
  })
}

🔧 故障排除

常见问题

Q: 样式不显示或错乱? A: 最常见的原因是没有在 CSS 中添加 @source 指令。请确保: 1. 在主 CSS 文件中添加了 @source "../node_modules/@aiwanna-team/message-list"; 2. 项目使用的是 TailwindCSS 4.0+ 3. 检查控制台是否有 TailwindCSS 相关的错误信息

Q: 历史消息加载不触发? A: 检查 onLoadHistory 回调是否正确设置,确保有足够的初始消息支持滚动

Q: 消息更新不生效? A: 确保使用正确的消息 key,检查 updateMessage 调用

Q: 性能问题? A: 调整 historyLoadLimit 和虚拟滚动配置,避免一次性加载过多消息

📄 许可证

MIT License

🤝 贡献

欢迎提交 Issue 和 Pull Request!


官方文档: 查看 Storybook 演示 GitHub: aiwanna-team/message-list

0.1.1

4 months ago

0.1.2

4 months ago

0.1.0

4 months ago