使用 offset().top 滚动到错误的地方

Posted

技术标签:

【中文标题】使用 offset().top 滚动到错误的地方【英文标题】:Scrolling using offset().top goes to the wrong place 【发布时间】:2017-01-10 17:48:14 【问题描述】:

我有一个包含两个 div 的页面 - 一个包含一个表格并且不是固定高度,另一个包含多个表格并且是基于第一个 div 的固定高度(自动溢出-y)。

HTML:

<div id="tables-container" style="height: 100vh;">
    <div id="outstanding-table">
        <table>
            <thead>
                <tr>
                    <th>Column 1</th>
                    <th>Column 2</th>
                    <th>Column 3</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Column 1</td>
                    <td>Column 2</td>
                    <td>Column 3</td>
                </tr>
                ...more rows...
                <tr>
                    <td>Column 1</td>
                    <td>Column 2</td>
                    <td>Column 3</td>
                </tr>
            </tbody>
        </table>
    </div>

    <hr>

    <div id="overview-tables" style="overflow-y: auto;">
        <h3 id="table-1">Table 1</h3>
        <table>
            <thead>
                <tr>
                    <th>Column 1</th>
                    <th>Column 2</th>
                    <th>Column 3</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Column 1</td>
                    <td>Column 2</td>
                    <td>Column 3</td>
                </tr>
                ...more rows...
                <tr>
                    <td>Column 1</td>
                    <td>Column 2</td>
                    <td>Column 3</td>
                </tr>
            </tbody>
        </table>

        <h3 id="table-2">Table 2</h3>
        <table>
            <thead>
                <tr>
                    <th>Column 1</th>
                    <th>Column 2</th>
                    <th>Column 3</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Column 1</td>
                    <td>Column 2</td>
                    <td>Column 3</td>
                </tr>
                ...more rows...
                <tr>
                    <td>Column 1</td>
                    <td>Column 2</td>
                    <td>Column 3</td>
                </tr>
            </tbody>
        </table>

        <h3 id="table-3">Table 3</h3>
        <table>
            <thead>
                <tr>
                    <th>Column 1</th>
                    <th>Column 2</th>
                    <th>Column 3</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Column 1</td>
                    <td>Column 2</td>
                    <td>Column 3</td>
                </tr>
                ...more rows...
                <tr>
                    <td>Column 1</td>
                    <td>Column 2</td>
                    <td>Column 3</td>
                </tr>
            </tbody>
        </table>
        ...more tables...
    </div>
</div>

JS:

$(document).ready(function () 
    var overviewTablesHeight = $('#tables-container').innerHeight() - $('#outstanding-table').innerHeight() - 50;
    $('#overview-tables').innerHeight(overviewTablesHeight);

    var timeoutTime = 1000;
    var tableId = getFirstTableId();

    scrollDown();

    function getFirstTableId() 
        var id = 'table-1';
        return id;
    

    function getNextTableId() 
        var tableIdParts = tableId.split('-');
        var id = tableIdParts[0] + '-' + (parseInt(tableIdParts[1]) + 1);
        return id;
    

    function scrollDown() 
        setTimeout(function () 
            tableId = getNextTableId();

            var scrollTo = $('#' + tableId).position().top - $('#overview-tables').offset().top;
            console.log($('#' + tableId).offset().top + ' - ' + $('#overview-tables').offset().top + ' = ' + scrollTo);
            scroll(scrollTo);

            var isBottom = $('#overview-tables').scrollTop() + $('#overview-tables').innerHeight() >= $('#overview-tables')[0].scrollHeight;
            if (isBottom) 
                scrollUp();
            
            else 
                scrollDown();
            
        , timeoutTime);
    

    function scrollUp() 
        setTimeout(function () 
            scroll(0);
            tableId = getFirstTableId();
            scrollDown();
        , timeoutTime);
    

    function scroll(scrollTopValue) 
        $('#overview-tables').animate( scrollTop: scrollTopValue , 'fast');
    
);

我试图让底部部分依次自动向下滚动到每个h3(使用this answer 的想法)直到它到达底部,此时它将滚动回顶部并开始再次。但是,offset().top 似乎没有给出正确的值。例如,第三个表格的偏移值将低于第二个表格,导致它向上滚动一点,而不是向下滚动。

这是一个Bootply 来显示问题。我添加了控制台日志,以便您可以看到正在计算的值。


我已经看过这些问题,但似乎都在谈论检查边距、图像、填充等,但在我上面的 Bootply 中我没有边距,而且不正确的值似乎没有出现每次相同的数量:

jQuery offset().top returns wrong value - error with margin jQuery offset is not calculating correctly on some pages jQuery offset top doesn't work correctly jquery inconsistent positioning using offset().top .offset().top returning the wrong value Jquery scrollTop goes to the wrong position

【问题讨论】:

【参考方案1】:

我刚刚发现this answer 几乎解决了我的滚动问题,但是我必须添加一些额外内容才能使其在我的情况下正常工作。这是我更新后的 scrollDown 函数:

function scrollDown() 
    setTimeout(function () 
        tableId = getNextTableId();

        var scrollTo = $('#' + tableId).position().top + $('#overview-tables').scrollTop() - $('#outstanding-table').innerHeight();
        scroll(scrollTo);

        var isBottom = $('#overview-tables').scrollTop() + $('#overview-tables').innerHeight() >= $('#overview-tables')[0].scrollHeight;
        if (isBottom) 
            scrollUp();
        
        else 
            scrollDown();
        
    , timeoutTime);

【讨论】:

以上是关于使用 offset().top 滚动到错误的地方的主要内容,如果未能解决你的问题,请参考以下文章

滚动页面到 div

滚动页面到 div

JQ的offset().top与JS的getBoundingClientRect区别详解,JS获取元素距离视窗顶部可变距离

如何通过JQuery将DIV的滚动条滚动到指定的位置

TypeError jQuery offset().top 未定义

如何在 forEach 循环中使用 offset().top