背景
在项目开发中,实现用户友好的输入交互是提升用户体验的关键之一。例如,在消息会话页面中,为了确保用户在发送新消息后页面能自动滚动到最底部,从而始终保持最新消息的可见性,需要实现自动滚动功能。这不仅提升了用户体验,还使得用户能够实时关注对话的最新进展。
实现思路
- 监听消息列表的变化
- 在消息变化后自动滚动到最底部
示例代码
组件结构如下
<template><div><el-dialog width="68%" :visible.sync="isShow" :before-close="close" class="kefu" :show-close="false":close-on-click-modal="false"><div class="kefu-con"><i class="el-icon-close close" @click="close" /><div class="header"><img :src="kefuImg" alt=""><div class="title">小奶龙智能问答助手</div></div><div class="container" ref="container"><div class="content" ref="content"><div v-for="item in messageForm"><div class="reply-container" v-if="item.type === 'reply'"><div class="reply-content"><div class="img-con"><img :src="kefuImg" alt=""></div><div class="reply" @click="handleProxyClick"><div v-if="item.isXml" v-html="item.content"></div><p v-else>{{ item.content }}</p></div></div></div><div class="qs-container" v-if="item.type === 'qs'"><div class="qs-content"><div class="qs"><p>{{ item.content }}</p></div></div></div></div></div></div><div class="footer"><img :src="kefuImg" alt=""><div class="question-con"><el-input class="ipt" v-model="question" placeholder="请输入想咨询的问题"></el-input><el-button class="btn" type="warning" round @click="send">发送</el-button></div></div></div></el-dialog></div>
</template><script>
import { getAnswer } from '@/api/checkin.js';
export default {data() {return {isShow: false,kefuImg: require("@/assets/images/headshot.png"),question: '',messageForm: [{content: "<p>您好, 我是您的小奶龙,你的智能助手。 你可以问我编码相关的问题,也可以一起更高效、更高质量地完成编码工作。比如 “<span class='quick' style='color: #5094d5;cursor: pointer;' @click='quick'>动态路由实现</span>”, “<span class='quick' style='color: #5094d5;cursor: pointer;' @click='quick'>移动端适配</span>” 等等一些问题。</p>",type: "reply", // reply 回答 qs 问题isXml: true,},{content: '动态路由实现',type: "qs", // reply 回答 qs 问题isXml: false,}]}},methods: {handleProxyClick(event) {// 获取触发事件的目标元素 event 事件对象const target = event.target;// 判断目标元素是否包含指定类名if (target.classList.contains('quick')) {// 传递目标元素的文本内容this.quick(target.outerText);}},quick(text) {console.log('quick方法触发了::: ');this.question = text;// 发送this.send();},show() {this.isShow = true;},close() {this.isShow = false;},send() {let NewQuestion = this.question.trim();if (NewQuestion === '') {return;}this.messageForm.push({content: NewQuestion,type: 'qs',isXml: false,});setTimeout(() => {this.question = '';})},},
}
</script>
发送消息不滚动到最底部
解决方法
获取对话框内容 DOM 元素,将滚动容器的滚动条位置设置为其最大高度,从而使滚动容器自动滚动到最底部
container.scrollTop
-
获取当前滚动容器的垂直滚动距离。
-
设置 scrollTop 的值可以改变滚动容器的滚动位置。
-
如果 scrollTop 设置为 0,则滚动到顶部;如果设置为某个较大的值,则滚动到对应的位置。
container.scrollHeight
-
获取滚动容器的总高度(包括不可见部分)。
-
当
scrollTop
设置为scrollHeight
时,滚动容器会滚动到最底部。
// 获取内容容器
const content = this.$refs.content;this.$refs.container.scrollTo(0, content.scrollHeight);
效果如下
当异步接口返回时,插入的内容不会滚动到最底部,我们需要使用 this.$nextTick()
函数,该函数会等待 DOM 更新完成后才调用
export default {methods: {send() {let NewQuestion = this.question.trim();if (NewQuestion === '') {return;}this.messageForm.push({content: NewQuestion,type: 'qs',isXml: false,});setTimeout(() => {// 模拟异步请求this.messageForm.push({content: '11111',type: 'reply',isXml: false,});this.question = '';this.$nextTick(() => {// 滚动到底部this.scrollToBottom();})})},scrollToBottom() {const content = this.$refs.content;this.$refs.container.scrollTo(0, content.scrollHeight);}}
}
效果如下
总结
在设计实现消息会话页面时,为确保每次发送新消息后,页面自动滚动至底部,关键在于利用 Vue 的响应式特性结合 DOM 操作技巧。具体策略为:当消息列表数据更新后,利用 this.$nextTick()
确保 DOM 已完成更新,随后设置容器的 scrollTop
属性等于 scrollHeight
,从而使页面平滑地滚动到消息区域的最底部,以此提升用户体验,保证用户始终能便捷地查看最新的聊天内容。