背景
在使用ai助手聊天的时候,每当聊天框中展示新消息,需要将聊天框滚动到底部,展示最新信息。跟普通聊天工具相比,ai助手聊天使用的是流响应,消息体会随着ai模型的输出不断变化。
实现思路
- 监听消息体的变化,频繁的进行javascript调用滚动到底部(极度不推荐,一听就有性能问题)。
- 参考Poe的聊天框实现方式,通过改变消息列表的排列方向来实现 (推荐)。
实现的功能
- 当发送新消息时,滚动到聊天框底部
这一点比较简单,在发送的时候滚动到底部
关键代码:
sendMessage() {
this.list.push({ id: this.list.length + 1, message: this.message });
// 平滑滚动到.container的底部
this.$nextTick(() => {
document.querySelector('.container').scrollTop = 0
})
},
- 在聊天框底部接受消息体期间,滚动条一直处于最底部
注意:这里是实现方式的关键:
首先,需要将 .box 的样式设置为:
display: flex;
flex-direction: column-reverse;
效果对比:
针对数据较少时的空白块,我们通过添加 .empty-box 元素来进行填充,给元素添加以下样式,在有空白时撑开剩余空间,数据多时高度为0。
flex-grow: 1;
代码实现
demo演示:
组件代码:
<template>
<div class="container">
<div class="box">
<div class="list">
<div class="item" v-for="item in list" :key="item.id">{{ item.message }}</div>
</div>
<div class="empty-box"></div>
<div class="footer">
<input type="text" v-model="message" />
<button @click="sendMessage">发送</button>
<button @click="addMessageText">加文字</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Demo001',
data() {
return {
message: '',
list: [
{
id: 1,
message: '这是第一条消息',
},
{
id: 2,
message: '这是第二条消息',
},
{
id: 3,
message: '这是第3条消息',
},
{
id: 4,
message: '这是第4条消息',
},
{
id: 5,
message: '这是第5条消息',
},
{
id: 6,
message: '这是第6条消息',
},
{
id: 7,
message: '这是第7条消息',
},
{
id: 8,
message: '这是第8条消息',
}
]
}
},
methods: {
sendMessage() {
this.list.push({ id: this.list.length + 1, message: this.message });
// 平滑滚动到.container的底部
this.$nextTick(() => {
document.querySelector('.container').scrollTop = 0
})
},
addMessageText() {
this.list[this.list.length - 1].message = this.list[this.list.length - 1].message + ' ' + this.message
}
}
}
</script>
<style lang="scss">
.container {
height: 500px;
width: 400px;
overflow-y: scroll;
overflow-x: hidden;
display: flex;
flex-direction: column-reverse;
padding: 0 16px;
border: 2px solid #eee;
scroll-behavior: smooth;
.box {
width: 100%;
flex: 1 1;
align-self: center;
display: flex;
flex-direction: column;
.list {
display: flex;
flex-direction: column;
}
.empty-box {
flex-grow: 1;
}
.footer {
position: sticky;
width: 100%;
bottom: 0;
background: #fff;
}
}
}
</style>