Skip to content

Repository files navigation

xzx-chat-kit

一个跨前端框架的聊天组件库,支持 Vue 2、Vue 3 和 React。

特性

  • 🚀 支持 Vue 2.6+ 和 Vue 3
  • ⚛️ 支持 React 16.8+
  • 📦 使用 TypeScript 编写
  • 🎯 零依赖核心库
  • 🔧 使用 vue-demi 实现 Vue 版本兼容
  • 🎨 样式文件可独立导入
  • 🎯 支持自定义插槽
  • 💫 支持消息状态管理
  • 🎨 支持主题定制
  • ⌨️ 内置打字机效果
  • 🗑️ 支持消息删除和清空

安装

npm install xzx-chat-kit
#
pnpm add xzx-chat-kit
#
yarn add xzx-chat-kit

Vue 2 额外依赖

如果你使用 Vue 2,还需要安装 @vue/composition-api

npm install @vue/composition-api

使用方法

自动导入样式

组件会自动导入所需的样式,无需手动导入。

手动导入样式

如果您希望手动控制样式导入,可以单独导入:

// 导入样式文件
import 'xzx-chat-kit/styles'
// 或
import 'xzx-chat-kit/dist/styles/index.css'

Vue 3

<template>
  <div>
    <ChatBox :chat-core="chatCore">
      <!-- 自定义开始区域 -->
      <template #start-here>
        <div class="start-message">
          <span>👋 开始愉快的聊天吧!</span>
        </div>
      </template>

      <!-- 自定义空状态 -->
      <template #empty>
        <div class="custom-empty-state">
          <p>还没有消息哦,快来开始聊天吧!</p>
        </div>
      </template>

      <!-- 自定义消息内容 -->
      <template #message="{ content, component, componentProps }">
        <span v-if="content?.message || content">{{
          content?.message || content
        }}</span>
        <component v-if="component" :is="component" v-bind="componentProps" />
      </template>

      <!-- 自定义输入框 -->
      <template #input="{ value, onInput, onSend, placeholder }">
        <div class="custom-input-wrapper">
          <textarea
            :value="value"
            @input="(e) => onInput(e.target.value)"
            :placeholder="placeholder"
            @keyup.enter.ctrl="onSend" />
          <button @click="onSend">发送</button>
        </div>
      </template>
    </ChatBox>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { ChatBox } from 'xzx-chat-kit/vue'
import { ChatCore, typewriterEffect } from 'xzx-chat-kit'

const messages = ref([])

// 创建 ChatCore 实例
const chatCore = new ChatCore({
  currentUser: 'user',
  placeholder: '请输入您的消息...',
  showAvatar: true,
  messages: messages.value,
  onSendMessage: async (message, history) => {
    console.log('发送消息:', message)
    console.log('历史记录:', history)

    // 模拟机器人回复
    await simulateBot(message)
  }
})

// 使用打字机效果模拟机器人回复
const simulateBot = async (userMessage) => {
  const messageContent = ref('')

  // 添加空消息
  chatCore.addMessage({
    id: Date.now(),
    content: messageContent,
    sender: 'bot',
    timestamp: Date.now(),
    type: 'text'
  })

  // 使用打字机效果
  await typewriterEffect(`你说: ${userMessage}`, messageContent, {
    speed: 50,
    delay: 500
  })
}
</script>

Vue 2

<template>
  <div>
    <ChatBox :chat-core="chatCore">
      <template #start-here>
        <div class="start-message">
          <span>👋 开始愉快的聊天吧!</span>
        </div>
      </template>

      <template #empty>
        <div class="custom-empty-state">
          <p>还没有消息哦,快来开始聊天吧!</p>
        </div>
      </template>

      <template #message="{ content, component, componentProps }">
        <span v-if="content.message || content">{{
          content.message || content
        }}</span>
        <component v-if="component" :is="component" v-bind="componentProps" />
      </template>
    </ChatBox>
  </div>
</template>

<script>
import { ref } from 'vue-demi'
import { ChatBox } from 'xzx-chat-kit/vue'
import { ChatCore, typewriterEffect } from 'xzx-chat-kit'

export default {
  components: {
    ChatBox
  },
  data() {
    const messages = ref([])

    return {
      chatCore: new ChatCore({
        currentUser: 'user',
        placeholder: '请输入您的消息...',
        showAvatar: true,
        messages: messages.value,
        onSendMessage: async (message, history) => {
          console.log('发送消息:', message)
          console.log('历史记录:', history)

          // 模拟机器人回复
          await this.simulateBot(message)
        }
      })
    }
  },
  methods: {
    async simulateBot(userMessage) {
      const messageContent = ref('')

      this.chatCore.addMessage({
        id: Date.now(),
        content: messageContent,
        sender: 'bot',
        timestamp: Date.now(),
        type: 'text'
      })

      await typewriterEffect(`你说: ${userMessage}`, messageContent, {
        speed: 50,
        delay: 500
      })
    }
  }
}
</script>

React

import React, { useRef, useState } from 'react'
import { ChatBox } from 'xzx-chat-kit/react'
import { ChatCore, typewriterEffect } from 'xzx-chat-kit'

function App() {
  const [messages] = useState([])
  const chatCoreRef = useRef(null)

  // 创建 ChatCore 实例
  if (!chatCoreRef.current) {
    chatCoreRef.current = new ChatCore({
      currentUser: 'user',
      placeholder: '请输入您的消息...',
      showAvatar: true,
      messages: messages,
      onSendMessage: async (message, history) => {
        console.log('发送消息:', message)
        console.log('历史记录:', history)

        // 模拟机器人回复
        await simulateBot(message)
      }
    })
  }

  // 使用打字机效果模拟机器人回复
  const simulateBot = async (userMessage) => {
    const messageContent = { value: '' }

    chatCoreRef.current.addMessage({
      id: Date.now(),
      content: messageContent,
      sender: 'bot',
      timestamp: Date.now(),
      type: 'text'
    })

    // 模拟打字机效果(React 版本需要手动实现响应式更新)
    const text = `你说: ${userMessage}`
    let index = 0
    const typeInterval = setInterval(() => {
      messageContent.value = text.slice(0, index + 1)
      index++
      if (index >= text.length) {
        clearInterval(typeInterval)
      }
    }, 50)
  }

  return (
    <div>
      <ChatBox
        chatCore={chatCoreRef.current}
        startHereSlot={
          <div className="start-message">
            <span>👋 开始愉快的聊天吧!</span>
          </div>
        }
        emptySlot={
          <div className="custom-empty-state">
            <p>还没有消息哦,快来开始聊天吧!</p>
          </div>
        }
        messageSlot={({ content, component, componentProps }) => (
          <>
            {content ? <span>{content}</span> : null}
            {component && <component {...componentProps} />}
          </>
        )}
        inputSlot={({ value, onChange, onSend, placeholder }) => (
          <div className="custom-input-wrapper">
            <textarea
              value={value}
              onChange={onChange}
              placeholder={placeholder}
              onKeyUp={(e) => e.ctrlKey && e.key === 'Enter' && onSend()}
            />
            <button onClick={onSend}>发送</button>
          </div>
        )}
      />
    </div>
  )
}

export default App

作为插件使用

// Vue 3
import { createApp } from 'vue'
import XzxChatKit from 'xzx-chat-kit/vue'
import App from './App.vue'

const app = createApp(App)
app.use(XzxChatKit)
app.mount('#app')

// Vue 2
import Vue from 'vue'
import XzxChatKit from 'xzx-chat-kit/vue'
import App from './App.vue'

Vue.use(XzxChatKit)

new Vue({
  render: (h) => h(App)
}).$mount('#app')

// 使用时仍需要创建 ChatCore 实例
// <template>
//   <ChatBox :chat-core="chatCore" />
// </template>

插槽

组件提供了以下插槽用于自定义内容:

start-here

在消息列表顶部显示的内容,通常用于显示开始聊天的提示或欢迎信息。

<template>
  <ChatBox :chat-core="chatCore">
    <template #start-here>
      <div class="welcome-message">
        <h3>👋 欢迎使用聊天助手</h3>
        <p>点击下方按钮开始对话</p>
        <button @click="startChat">开始聊天</button>
      </div>
    </template>
  </ChatBox>
</template>

empty

当消息列表为空时显示的内容。

message

自定义消息内容的渲染方式。

input

自定义输入框区域的渲染方式。

样式定制

所有的 CSS 类都以 ck- 前缀命名,您可以通过覆盖这些类来自定义样式:

/* 自定义容器样式 */
.ck-chat-box {
  background: #f0f0f0;
  border-radius: 12px;
}

/* 自定义按钮样式 */
.ck-send-button {
  background: #666666;
}

.ck-send-button:hover {
  background: #808080;
}

CSS 变量

组件使用 CSS 变量来管理主题,您可以通过覆盖这些变量来自定义主题:

:root {
  /* 主题色 */
  --ck-primary-color: #666666;
  --ck-primary-hover: #808080;
  --ck-primary-active: #4d4d4d;

  /* 背景色 */
  --ck-bg-color: #ffffff;
  --ck-bg-hover: #f5f5f5;
  --ck-bg-active: #e6e6e6;

  /* 文字颜色 */
  --ck-text-color: #666666;
  --ck-text-secondary: #808080;
  --ck-text-disabled: #999999;

  /* 边框颜色 */
  --ck-border-color: #e6e6e6;
  --ck-border-hover: #d9d9d9;

  /* 消息气泡颜色 */
  --ck-message-bg: #f5f5f5;
  --ck-message-user-bg: #e6e6e6;
  --ck-message-text: #666666;
}

API 文档

ChatCore

聊天组件的核心数据管理类。

构造函数

const chatCore = new ChatCore(options)

方法

方法 参数 返回值 描述
getState() - ChatState 获取当前状态
getMessages() - Message[] 获取消息列表
addMessage(message) Message void 添加消息
sendMessage(content) string void 发送消息
updateMessageStatus(id, status) string | number, MessageStatus void 更新消息状态
clearMessages() - void 清空所有消息
deleteMessage(id) string | number boolean 删除指定消息
setMessagesChangeCallback(callback) (messages: Message[]) => void void 设置消息变化回调

ChatOptions

属性 类型 默认值 描述
currentUser string 'user' 当前用户标识
messages Message[] [] 初始消息列表
placeholder string '请输入消息...' 输入框占位符
showAvatar boolean true 是否显示头像
onSendMessage (message: string, history: ChatHistoryItem[]) => void - 发送消息回调,包含历史记录
onMessageStatusChange (messageId: string | number, status: MessageStatus) => void - 消息状态变化回调

ChatHistoryItem

聊天历史记录项,用于 onSendMessage 回调的第二个参数。

属性 类型 描述
message any 消息内容
isUser boolean 是否用户消息
timestamp number 时间戳

Message

属性 类型 描述
id string | number 消息唯一标识
content string | Ref<string> 消息内容(支持响应式)
sender string 发送者
isUser boolean 是否为用户消息
timestamp number 发送时间戳
type 'text' | 'image' | 'file' | 'component' 消息类型
status 'sending' | 'sent' | 'read' | 'failed' 消息状态
avatar string 头像 URL
component Component 自定义组件
componentProps any 组件属性

版本兼容性

框架 版本要求
Vue 2 >= 2.6.0
Vue 3 >= 3.0.0
React >= 16.8.0

开发

# 安装依赖
pnpm install

# 构建
pnpm build

# 构建单独的包
pnpm build:core    # 核心库
pnpm build:vue     # Vue 组件 (支持 Vue 2 & 3)
pnpm build:react   # React 组件
pnpm build:styles  # 复制样式文件

打字机效果

组件库内置了打字机效果功能,可以让文本逐字显示。

基本用法

import { typewriterEffect, createTypewriter } from 'xzx-chat-kit'
import { ref } from 'vue' // 或 'vue-demi'

// 方式1: 简单的 Promise 方式
const messageContent = ref('')
await typewriterEffect('Hello, World!', messageContent, {
  speed: 50, // 每个字符显示间隔(毫秒)
  delay: 500, // 开始前延迟(毫秒)
  onProgress: (currentText, progress) => {
    console.log(`进度: ${Math.round(progress * 100)}%`)
  },
  onComplete: () => {
    console.log('打字完成!')
  }
})

// 方式2: 更强的控制方式
const { displayText, controller } = createTypewriter('Hello, World!', {
  speed: 50,
  delay: 500
})

// 控制打字机
controller.start() // 开始
controller.pause() // 暂停
controller.resume() // 继续
controller.stop() // 停止
controller.reset() // 重置

// 检查状态
console.log(controller.isRunning()) // 是否正在运行
console.log(controller.isPaused()) // 是否已暂停

配置选项

选项 类型 默认值 描述
speed number 50 每字符间隔(ms)
delay number 0 开始前延迟(ms)
onProgress (text: string, progress: number) => void - 进度回调
onComplete () => void - 完成回调

许可证

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages