一个跨前端框架的聊天组件库,支持 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/composition-api:
npm install @vue/composition-api组件会自动导入所需的样式,无需手动导入。
如果您希望手动控制样式导入,可以单独导入:
// 导入样式文件
import 'xzx-chat-kit/styles'
// 或
import 'xzx-chat-kit/dist/styles/index.css'<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><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>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>组件提供了以下插槽用于自定义内容:
在消息列表顶部显示的内容,通常用于显示开始聊天的提示或欢迎信息。
<template>
<ChatBox :chat-core="chatCore">
<template #start-here>
<div class="welcome-message">
<h3>👋 欢迎使用聊天助手</h3>
<p>点击下方按钮开始对话</p>
<button @click="startChat">开始聊天</button>
</div>
</template>
</ChatBox>
</template>当消息列表为空时显示的内容。
自定义消息内容的渲染方式。
自定义输入框区域的渲染方式。
所有的 CSS 类都以 ck- 前缀命名,您可以通过覆盖这些类来自定义样式:
/* 自定义容器样式 */
.ck-chat-box {
background: #f0f0f0;
border-radius: 12px;
}
/* 自定义按钮样式 */
.ck-send-button {
background: #666666;
}
.ck-send-button:hover {
background: #808080;
}组件使用 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;
}聊天组件的核心数据管理类。
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 |
设置消息变化回调 |
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
currentUser |
string |
'user' |
当前用户标识 |
messages |
Message[] |
[] |
初始消息列表 |
placeholder |
string |
'请输入消息...' |
输入框占位符 |
showAvatar |
boolean |
true |
是否显示头像 |
onSendMessage |
(message: string, history: ChatHistoryItem[]) => void |
- | 发送消息回调,包含历史记录 |
onMessageStatusChange |
(messageId: string | number, status: MessageStatus) => void |
- | 消息状态变化回调 |
聊天历史记录项,用于 onSendMessage 回调的第二个参数。
| 属性 | 类型 | 描述 |
|---|---|---|
message |
any |
消息内容 |
isUser |
boolean |
是否用户消息 |
timestamp |
number |
时间戳 |
| 属性 | 类型 | 描述 |
|---|---|---|
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