引言
在我参与智能问答项目中一个智能体回话并不会像豆包一样,每次新建会话都是是从头开始,而项目中你想创建新会话就像chatbox一样,是点击橡皮擦开启新的聊天上下文,但是直接的聊天记录依然存在,针对超过十万+条对话数据进行展示。会出现页面卡死的问题。
所以我们可以通过虚拟列表
的形式展示我们的对话内容
<template>
<div class="container">
<!-- 展示问答内容 -->
<div class="chat-container" ref="chatContainer" @scroll="handleScroll">
<!-- 优化后 -->
<div
class="virtual-placeholder"
:style="{ height: `${chatListHeight}px` }"
></div>
<div
class="truth-box"
:style="{ transform: `translateY(${scrollTop}px)` }"
>
<div
class="chat-item-container"
:style="{ transform: `translateY(${scrollTopItem}px)` }"
>
<div
v-for="(item, index) in renderedItems"
:key="index"
class="chat-item"
:style="{ height: `${item.height}px` }"
>
<div v-if="item.isUser" class="user-message">
{{ item.content }}
</div>
<div v-else class="system-message">{{ item.content }}</div>
</div>
</div>
</div>
<!-- ------------------------------------------- -->
<!-- 优化前 -->
<!-- <div
v-for="(item, index) in chatList"
:key="index"
class="chat-item"
:style="{ height: `${item.height}px` }"
>
<div v-if="item.isUser" class="user-message">{{ item.content }}</div>
<div v-else class="system-message">{{ item.content }}</div>
</div> -->
</div>
<!-- 输入框与发送按钮 -->
<el-row type="flex" justify="center">
<el-col :span="18">
<el-input v-model="inputValue" placeholder="请输入内容"></el-input>
</el-col>
<el-col :span="6">
<el-button type="primary" @click="send">发送</el-button>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
data() {
return {
inputValue: '',
chatList: [],
startIndex: 0,
visibleCount: 20, // 可视区域内显示的条目数
itemHeight: 100, // 假设每个条目平均高度为 100px
scrollTop: 0,
}
},
computed: {
chatListLength() {
return this.chatList.length
},
chatListHeight() {
return (
(this.chatList.reduce((acc, item) => acc + item.height, 0) *
this.chatListLength) /
this.chatListLength
)
},
renderedItems() {
console.log('renderedItems', this.startIndex)
return this.chatList.slice(
this.startIndex,
this.startIndex + this.visibleCount
)
},
startOffset() {
return this.chatList
.slice(0, this.startIndex)
.reduce((acc, item) => acc + item.height, 0)
},
scrollTopItem() {
return this.startOffset - this.scrollTop
},
},
mounted() {
this.chatList = new Array(100000).fill(0).map(() => {
return {
isUser: Math.random() > 0.5,
content: '欢迎来到我们的帮助中心!',
height: Math.random() * 100 + 50,
}
})
},
methods: {
send() {
if (this.inputValue.trim() !== '') {
// 添加用户的输入到聊天列表
this.chatList.push({
isUser: true,
content: this.inputValue,
height: Math.random() * 100 + 50,
})
// 模拟系统回复
setTimeout(() => {
this.chatList.push({
isUser: false,
content: '你可以通过点击设置选项来修改账户信息。',
height: Math.random() * 100 + 50,
})
}, 500)
// 清空输入框
this.inputValue = ''
// 自动滚动到底部
this.scrollToBottom()
}
},
handleScroll() {
const scrollTop = this.$refs.chatContainer.scrollTop
this.scrollTop = scrollTop
let currentStartIndex = 0
let totalHeiight = 0
for (let i = 0; i < this.chatList.length; i++) {
const item = this.chatList[i]
totalHeiight += item.height
if (totalHeiight >= scrollTop) {
currentStartIndex = i
break
}
}
this.startIndex = currentStartIndex >= 0 ? currentStartIndex : 0
},
scrollToBottom() {
this.$nextTick(() => {
const container = this.$refs.chatContainer
// 正确设置滚动到底部
container.scrollTop = container.scrollHeight
})
},
},
}
</script>
<style lang="scss" scoped>
.container {
display: flex;
flex-direction: column;
height: 100%;
}
.chat-container {
flex: 1;
height: 0;
overflow-y: auto;
position: relative;
.truth-box {
width: 100%;
position: absolute;
top: 0;
left: 0;
overflow: hidden;
height: 100%;
}
}
.chat-item-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
.chat-item {
}
.user-message {
text-align: right;
color: #409eff; // Element UI 蓝色
background: pink;
height: 100%;
}
.system-message {
height: 100%;
text-align: left;
color: #67c23a; // Element UI 绿色
background: gray;
}
</style>