You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实时聊天jQuery自动滚动到底部失效问题求助

问题描述

开发实时聊天功能时,整体运行正常,但用户在2-5秒内连续发送3-4条消息时,聊天框无法自动滚动到底部。当前通过setInterval每秒调用updateChat函数获取新消息,相关代码如下:

$(document).on('keypress', 'textarea[name=message]', function(e) {
   if(e.which == 13) {
    e.preventDefault();

    var myform = $('.sendMessage')[0];
    var formData = new FormData(myform);

    $.ajax({
        url  : $('.sendMessage').attr('action'),
        type : 'POST',
        data : formData,
        processData: false,
        contentType: false,
        dataType: 'json',
        success: function( response ) {
            var scrollPosition = false;

            if (($('#chat')[0].scrollHeight - $('#chat').scrollTop()).toFixed() == $('#chat').outerHeight()) {
                scrollPosition = true;
            } 

            $('#chat').append(response.message);

            if(scrollPosition == true) {
                $('#chat')[0].scrollTop = $('#chat')[0].scrollHeight;
                $('.jump-bottom').fadeOut();
            } else {
                $('.jump-bottom').fadeIn();
            }

            $('input[name=chatCount]').val(response.chatCount);

            activatePopup();
            
            $('.post-project-comment').html('');
            $('#basic_message').html('');
        },
        error : function(request, status, error) {
            $('#login-load').fadeOut();
        }
    });

    $(this).val('');
   }
 });

function updateChat(chatID, chatCount) {
var chatUrlSet = $('input[name=chatMainUrl]').val();

$.ajaxSetup({ cache: false });

$.ajax({
    url      : chatUrlSet + '/' + chatID + '/' + chatCount,
    type     : 'GET',
    dataType : 'json',
    success  : function( response ) {
        if(response.status == 1) {
            var scrollPosition = false;

            if (($('#chat')[0].scrollHeight - $('#chat').scrollTop()).toFixed() == $('#chat').outerHeight()) {
                scrollPosition = true;
            } 

            $('#chat').append(response.message);

            if(scrollPosition == true) {
                $('#chat')[0].scrollTop = $('#chat')[0].scrollHeight;
                $('.jump-bottom').fadeOut();
            } else {
                $('.jump-bottom').fadeIn();
            }

            $('input[name=chatCount]').val(response.chatCount);

            activatePopup();
        }               
    },
    error : function(request, status, error) {
        $('#login-load').fadeOut();
        console.log(request.responseText);
    }
});
}

if($('.individual-match-chat').length > 0) {    
setInterval(function() {
    var chatID    = $('input[name=thread]').val();
    var chatCount = $('input[name=chatCount]').val();

    if(chatID > 0) {
        updateChat(chatID, chatCount);
    }
}, 1000);
}
问题排查与解决方案

核心原因

  1. 滚动判断时机错误:在追加消息前判断滚动位置,连续发送消息时,前一条AJAX回调未完成就触发新请求,滚动高度计算与实际最终高度不一致,导致滚动逻辑失效。
  2. DOM渲染延迟:追加消息后立即设置滚动,浏览器可能未完成新消息的DOM渲染,scrollHeight仍为旧值,导致滚动不到位。
  3. 并发AJAX冲突:连续发送触发多个AJAX请求,回调顺序混乱,滚动状态判断被打乱。
  4. 精度判断问题:使用toFixed()做严格相等判断,像素计算的微小误差会导致判断失败。

修复步骤

1. 调整滚动判断与执行时机

将滚动位置判断移到消息追加之后,并用requestAnimationFrame确保DOM渲染完成后再执行滚动,保证scrollHeight为最新值:

修改发送消息和updateChat的成功回调逻辑:

// 先追加消息
$('#chat').append(response.message);

// 确保DOM更新后计算滚动
requestAnimationFrame(function() {
    var chatElement = $('#chat')[0];
    // 宽松判断:距离底部小于20px即视为在底部,避免精度问题
    var isAtBottom = (chatElement.scrollHeight - chatElement.scrollTop - chatElement.clientHeight) < 20;
    
    if(isAtBottom) {
        chatElement.scrollTop = chatElement.scrollHeight;
        $('.jump-bottom').fadeOut();
    } else {
        $('.jump-bottom').fadeIn();
    }
});

2. 添加发送锁机制

避免短时间内重复发送消息,防止AJAX回调混乱:

// 全局作用域添加锁变量
var isSending = false;

$(document).on('keypress', 'textarea[name=message]', function(e) {
   if(e.which == 13 && !isSending) {
    e.preventDefault();
    isSending = true; // 上锁

    var myform = $('.sendMessage')[0];
    var formData = new FormData(myform);

    $.ajax({
        // 原有配置不变
        success: function( response ) {
            // 原有逻辑不变
            isSending = false; // 解锁
        },
        error : function(request, status, error) {
            $('#login-load').fadeOut();
            isSending = false; // 错误时也要解锁
        }
    });

    $(this).val('');
   }
 });

3. 优化轮询逻辑

将setInterval改为递归setTimeout,确保上一次AJAX请求完成后再发起下一次,避免请求堆积:

function pollChat() {
    var chatID    = $('input[name=thread]').val();
    var chatCount = $('input[name=chatCount]').val();

    if(chatID > 0) {
        updateChat(chatID, chatCount).then(function() {
            setTimeout(pollChat, 1000);
        }).catch(function() {
            setTimeout(pollChat, 1000);
        });
    } else {
        setTimeout(pollChat, 1000);
    }
}

// 修改updateChat返回Promise
function updateChat(chatID, chatCount) {
    return new Promise(function(resolve, reject) {
        var chatUrlSet = $('input[name=chatMainUrl]').val();

        $.ajaxSetup({ cache: false });

        $.ajax({
            // 原有配置不变
            success  : function( response ) {
                // 原有逻辑不变
                resolve();
            },
            error : function(request, status, error) {
                $('#login-load').fadeOut();
                console.log(request.responseText);
                reject();
            }
        });
    });
}

if($('.individual-match-chat').length > 0) {    
    pollChat();
}

内容的提问来源于stack exchange,提问作者Usman Khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 00:13:24