You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在流式AI聊天响应过程中,避免用户手动向上滚动时被强制自动回滚到底部?

如何在流式AI聊天响应过程中,避免用户手动向上滚动时被强制自动回滚到底部?

这个问题我之前做类似ChatGPT的流式聊天界面时也踩过坑,核心就是给自动滚动加个"智能开关"——用户主动离开底部就暂停自动滚动,回到底部就恢复。下面是我验证过的可行方案,兼容桌面和移动端:

核心思路

  1. 用一个全局变量控制自动滚动的开关
  2. 监听聊天容器的滚动事件,实时判断用户是否在底部附近
  3. 只有当开关开启时,才在收到流式chunk时执行自动滚动
  4. 用户发送新消息时自动重置开关(毕竟用户主动发消息肯定想看到新回复)

具体代码修改步骤

1. 定义全局状态和容错阈值

在你的JS代码最外层(或者初始化函数里)添加这两个变量:

// 控制是否允许自动滚动到底部的开关
let shouldAutoScroll = true;
// 滚动阈值:距离底部小于10px就视为"在底部"(可根据需求调整)
const SCROLL_THRESHOLD = 10;

2. 初始化滚动监听器

添加一个监听滚动的函数,在页面加载完成后绑定到聊天容器:

function initScrollListener() {
  const chatContainer = document.getElementById('chat-container');
  
  chatContainer.addEventListener('scroll', () => {
    // 计算当前是否处于底部附近
    const isNearBottom = chatContainer.scrollTop + chatContainer.clientHeight >= chatContainer.scrollHeight - SCROLL_THRESHOLD;
    
    // 用户手动滚离底部 → 关闭自动滚动
    if (!isNearBottom && shouldAutoScroll) {
      shouldAutoScroll = false;
    } 
    // 用户滚回底部 → 开启自动滚动,同时立即修正位置
    else if (isNearBottom && !shouldAutoScroll) {
      shouldAutoScroll = true;
      chatContainer.scrollTop = chatContainer.scrollHeight;
      document.getElementById('chat-messages').scrollTop = document.getElementById('chat-messages').scrollHeight;
    }
  });
}

// 页面加载完成后初始化监听
document.addEventListener('DOMContentLoaded', initScrollListener);

3. 修改流式chunk的滚动逻辑

把你原来在requestAnimationFrame里的强制滚动代码,改成只有shouldAutoScrolltrue时才执行:

requestAnimationFrame(() => {
  // 仅当允许自动滚动时,才执行滚动操作
  if (shouldAutoScroll) {
    // 滚动到聊天消息容器底部
    chatMessages.scrollTop = chatMessages.scrollHeight;
    
    // 滚动到主聊天容器底部
    const chatContainer = document.getElementById('chat-container');
    chatContainer.scrollTop = chatContainer.scrollHeight;
    
    // 定位到流式光标
    const cursor = assistantMessageDiv.querySelector('.streaming-cursor');
    if (cursor) {
      cursor.scrollIntoView({ behavior: 'instant', block: 'nearest' });
    }
    
    // 滚动页面到底部(如果底部输入框存在)
    const bottomInput = document.getElementById('input-container-bottom');
    if (bottomInput && bottomInput.style.display !== 'none') {
      window.scrollTo({
        top: document.documentElement.scrollHeight,
        behavior: 'instant'
      });
    }
  }
});

4. 发送新消息时重置开关

sendStreamingRequest函数的开头,加上重置开关的代码——用户主动发消息,默认应该开启自动滚动:

function sendStreamingRequest(question, country, conversationHistory) {
  // 用户发新消息后,重置自动滚动状态为开启
  shouldAutoScroll = true;
  
  // ... 原来的代码继续执行
  console.log(' Starting STREAMING request...');
  // ...
}

关键细节说明

  • 阈值设计:用10px的阈值而非严格等于底部,是因为用户滚动时很难精准停在绝对底部,留一点容错空间体验更自然
  • 移动端兼容:你的CSS已经加了-webkit-overflow-scrolling: touch,这个滚动监听逻辑在移动端完全适用,不会有兼容性问题
  • 性能友好:滚动监听的计算逻辑非常简单,不会造成性能负担,不需要防抖也能流畅运行

测试要点

  1. 发送消息后,确认自动滚动到底部正常
  2. 手动向上滚动一段距离,此时新的流式chunk过来,不会被强制拉回底部
  3. 滚动回到底部10px范围内,自动滚动恢复,后续chunk会自动跟进到底部
  4. 移动端测试滚动行为,确保和桌面端一致

这样修改后,用户就能在流式响应过程中自由查看历史消息,又不会错过新内容的自动跟进,体验和ChatGPT就一致了~

火山引擎 最新活动