基于uniapp(TS+vue3)实现即时聊天页面,并将对方回复内容进行流式输出
·
<template>
<view class="chat-container">
<view class="chat-header">
<text>{{ title }}</text>
</view>
<view class="chat-body">
<view v-for="(message, index) in messages" :key="index"
:class="['chat-message', message.isSelf ? 'self' : 'other']">
<view class="avatar" v-if="!message.isSelf">
<image :src="otherUser.avatar" mode="aspectFit" class="avatar-image"></image>
</view>
<view class="message-content">
<view class="message-header">
<text v-if="message.isSelf">{{ selfUser.nickname }}</text>
<text v-else>{{ otherUser.nickname }}</text>
<text>{{ formatTime(message.timestamp) }}</text>
</view>
<text class="message-text" v-if="!message.isSelf || message.formattedText === message.text">{{ message.formattedText || message.text }}</text>
<text class="message-text" v-else>{{ message.formattedText }}</text>
</view>
<view class="avatar" v-if="message.isSelf">
<image :src="selfUser.avatar" mode="aspectFit" class="avatar-image"></image>
</view>
</view>
</view>
<view class="chat-input">
<input v-model="inputText" type="text" placeholder="输入消息" />
<button @click="sendMessage">发送</button>
</view>
</view>
</template>
<script lang="ts">
import { defineComponent, ref, reactive } from 'vue';
import { formatTime } from '@/utils/time'; // 时间格式化工具函数
export default defineComponent({
name: 'Chat',
setup() {
const selfUser = reactive({
avatar: 'https://example.com/self-avatar.jpg',
nickname: '自己'
});
const otherUser = reactive({
avatar: 'https://example.com/other-avatar.jpg',
nickname: '对方',
// 用户ID
id: 123
});
const messages = ref<Array<{
isSelf: boolean;
text: string;
timestamp: number;
formattedText: string; // 用于流式输出的格式化文本
}>>([]);
const inputText = ref('');
const title = '即时聊天';
// 修改流式输出函数,添加索引参数
const streamMessage = (message: { text: string; formattedText: string }, duration: number = 5000, index: number) => {
return new Promise((resolve) => {
let displayedText = '';
const charInterval = Math.ceil(duration / message.text.length); // 每个字符显示的时间间隔
const showNextChar = () => {
if (displayedText.length < message.text.length) {
displayedText += message.text[displayedText.length];
messages.value[index].formattedText = displayedText; // 更新消息对象的formattedText
requestAnimationFrame(showNextChar);
} else {
messages.value[index].formattedText = message.text; // 完成流式输出后,恢复为完整文本
resolve();
}
};
showNextChar();
});
};
const sendMessage = async () => {
if (inputText.value.trim() === '') return;
// 添加自己的消息到本地列表
const selfMessage = {
isSelf: true,
text: inputText.value,
timestamp: Date.now(),
formattedText: inputText.value // 初始化为自己的完整消息
};
messages.value.push(selfMessage);
// 清空输入框
inputText.value = '';
// 模拟对方回复
setTimeout(() => {
const otherMessage = {
isSelf: false,
text: `对方回复: ${'注:会员有效期为用户使用激活码后会员生效时间。时间段为用户使用激活码后仅在对应时间段内拥有会员权益;天数为用户使用激活码后对应天数内拥有会员权益。时间段激活码无法叠加使用,天数激活码可叠加使用累计天数。'}`,
timestamp: Date.now() + 2000, // 模拟对方延迟5秒回复
formattedText: '' // 初始化为空字符串,用于流式输出
};
const lastIndex = messages.value.push(otherMessage) - 1; // 获取新添加消息的索引
// 调用流式输出函数,并传入消息对象和新添加消息的索引
streamMessage(otherMessage, 6000, lastIndex).then(() => {
// 流式输出完成后,可以执行其他操作(如果有需要)
});
}, 2000);
};
return {
selfUser,
otherUser,
messages,
inputText,
title,
sendMessage,
formatTime
};
}
});
</script>
<style scoped>
.chat-container {
display: flex;
flex-direction: column;
height: 100vh;
}
.chat-header {
padding: 10px;
background-color: #f8f8f8;
text-align: center;
font-size: 18px;
}
.chat-body {
flex: 1;
overflow-y: auto;
padding: 10px;
}
.chat-message {
display: flex;
margin-bottom: 10px;
}
.self .avatar {
order: 2;
margin-left: 10px;
}
.other .avatar {
order: -1;
margin-right: 10px;
}
.avatar-image {
width: 40px;
height: 40px;
border-radius: 50%;
}
.message-content {
flex: 1;
padding: 10px;
border-radius: 10px;
max-width: 60%;
}
.self .message-content {
background-color: #dcf8c6;
align-self: flex-end;
}
.other .message-content {
background-color: #e0e0e0;
align-self: flex-start;
}
.message-header {
display: flex;
justify-content: space-between;
font-size: 14px;
color: #888;
}
.message-text {
font-size: 16px;
}
.chat-input {
display: flex;
padding: 10px;
background-color: #f8f8f8;
border-top: 1px solid #ddd;
}
input {
flex: 1;
padding: 5px;
border: 1px solid #ddd;
border-radius: 5px;
}
button {
height: 30px;
margin-left: 10px;
border: none;
background-color: #1aad19;
color: white;
border-radius: 5px;
font-size: 12px;
}
</style>
搭建uniapp(vue3+ts+vite)框架命令:
npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)