【问题标题】:How do I scroll to an element within an overflowed Div?如何滚动到溢出的 Div 中的元素?
【发布时间】:2010-02-27 02:28:22
【问题描述】:

我在一个 div 中有 20 个列表项,一次只能显示 5 个。滚动到项目#10,然后是项目#20 的好方法是什么?我知道所有物品的高度。

scrollTo 插件可以做到这一点,但如果不真正深入了解它的源代码,就不太容易理解。 我不想使用这个插件。

假设我有一个函数需要 2 个元素 $parentDiv$innerListItem$innerListItem.offset().top$innerListItem.positon().top 都没有为 $parentDiv 提供正确的 scrollTop。

【问题讨论】:

  • 由于您的更新而删除了我的答案。但相信我,之前也有过同样的态度,有很多浏览器的位置和边距等问题......插件是一条更简单的路线,耗时更少,而且只有 3k before GZip .
  • 无论如何都要使用 scrollTo 插件。这并不难。 $("#container").scrollTo(target, duration, options)。目标只是一个#anchor。完成。
  • 似乎应该有知识可以在没有插件的情况下做到这一点。明天生病开始阅读源代码
  • @mkoryak - 知识就在那里,但是当你考虑到浏览器的怪癖时,你基本上会得到...... .scrollTo 插件,所以为什么要重新 -一直在发明轮子?
  • 恕我直言,您最终可能会从 .scrollTo today 中获得所需的确切子集。但是几个月后,虽然 .scrollTo 已经更新到 IE9、FF4 和 Chrome 6,将不得不重新开始...... 3k 似乎是一个非常低的价格来避免这种情况。跨度>

标签: jquery


【解决方案1】:

$innerListItem.position().top 实际上是相对于其第一个定位祖先的.scrollTop()。因此,计算正确的$parentDiv.scrollTop() 值的方法是首先确保定位$parentDiv。如果它还没有明确的position,请使用position: relative。元素$innerListItem 及其直到$parentDiv 的所有祖先不需要有明确的位置。现在您可以滚动到$innerListItem

// Scroll to the top
$parentDiv.scrollTop($parentDiv.scrollTop() + $innerListItem.position().top);

// Scroll to the center
$parentDiv.scrollTop($parentDiv.scrollTop() + $innerListItem.position().top
    - $parentDiv.height()/2 + $innerListItem.height()/2);

【讨论】:

    【解决方案2】:

    这是我自己的插件(将元素放在列表的顶部。专门用于overflow-y : auto。可能不适用于overflow-x!):

    注意elem 是页面将滚动到的元素的 HTML 选择器。 jQuery 支持的任何东西,例如:#myiddiv.myclass$(jquery object)、[dom 对象] 等。

    jQuery.fn.scrollTo = function(elem, speed) { 
        $(this).animate({
            scrollTop:  $(this).scrollTop() - $(this).offset().top + $(elem).offset().top 
        }, speed == undefined ? 1000 : speed); 
        return this; 
    };
    

    如果您不需要动画,请使用:

    jQuery.fn.scrollTo = function(elem) { 
        $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem).offset().top); 
        return this; 
    };
    

    使用方法:

    $("#overflow_div").scrollTo("#innerItem");
    $("#overflow_div").scrollTo("#innerItem", 2000); //custom animation speed 
    

    注意:#innerItem 可以在 #overflow_div 内的任何位置。它不一定是直系孩子。

    在 Firefox (23) 和 Chrome (28) 中测试。

    如果要滚动整个页面,请检查this question

    【讨论】:

    • elem 是什么?你根本不解释。
    • 如果你将 fn.scrollTo 中的 $ 换成 jQuery,你可以获得更好的里程/无冲突
    • 这个有很大的缺陷,你不包含范围:$(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem, $(this)).offset().top); - 问候
    • 如果您想在页面和元素之间留出一些上边距(在某些情况下可能看起来更好),例如减去 10px,例如:$(this).scrollTop() - $(this).offset().top + $(elem).offset().top - 10
    • 如果您在 Firefox 和 Chrome(或其他浏览器)之间存在位置差异,请检查您的 html 代码(参见this bug report
    【解决方案3】:

    我已调整 Glenn Moss 的回答,以说明溢出 div 可能不在页面顶部。

    parentDiv.scrollTop(parentDiv.scrollTop() + (innerListItem.position().top - parentDiv.position().top) - (parentDiv.height()/2) + (innerListItem.height()/2)  )
    

    我在带有响应式模板的谷歌地图应用程序上使用它。在分辨率 > 800 像素时,列表位于地图的左侧。在分辨率

    【讨论】:

      【解决方案4】:

      上述答案会将内部元素定位在溢出元素的顶部,即使它在溢出元素内部的视图中也是如此。我不希望这样,所以我将其修改为如果元素在视图中则不更改滚动位置。

      jQuery.fn.scrollTo = function(elem, speed) {
          var $this = jQuery(this);
          var $this_top = $this.offset().top;
          var $this_bottom = $this_top + $this.height();
          var $elem = jQuery(elem);
          var $elem_top = $elem.offset().top;
          var $elem_bottom = $elem_top + $elem.height();
      
          if ($elem_top > $this_top && $elem_bottom < $this_bottom) {
              // in view so don't do anything
              return;
          }
          var new_scroll_top;
          if ($elem_top < $this_top) {
              new_scroll_top = {scrollTop: $this.scrollTop() - $this_top + $elem_top};
          } else {
              new_scroll_top = {scrollTop: $elem_bottom - $this_bottom + $this.scrollTop()};
          }
          $this.animate(new_scroll_top, speed === undefined ? 100 : speed);
          return this;
      };
      

      【讨论】:

        【解决方案5】:

        接受的答案仅适用于可滚动元素的直接子元素,而其他答案未将子元素置于可滚动元素的中心。

        示例 HTML:

        <div class="scrollable-box">
            <div class="row">
                <div class="scrollable-item">
                    Child 1
                </div>
                <div class="scrollable-item">
                    Child 2
                </div>
                <div class="scrollable-item">
                    Child 3
                </div>
                <div class="scrollable-item">
                    Child 4
                </div>
                <div class="scrollable-item">
                    Child 5
                </div>
                <div class="scrollable-item">
                    Child 6
                </div>
                <div class="scrollable-item">
                    Child 7
                </div>
                <div class="scrollable-item">
                    Child 8
                </div>
                <div class="scrollable-item">
                    Child 9
                </div>
                <div class="scrollable-item">
                    Child 10
                </div>
                <div class="scrollable-item">
                    Child 11
                </div>
                <div class="scrollable-item">
                    Child 12
                </div>
                <div class="scrollable-item">
                    Child 13
                </div>
                <div class="scrollable-item">
                    Child 14
                </div>
                <div class="scrollable-item">
                    Child 15
                </div>
                <div class="scrollable-item">
                    Child 16
                </div>
            </div>
        </div>
        
        <style>
        .scrollable-box {
            width: 800px;
            height: 150px;
            overflow-x: hidden;
            overflow-y: scroll;
            border: 1px solid #444;
        }
        .scrollable-item {
            font-size: 20px;
            padding: 10px;
            text-align: center;
        }
        </style>
        

        构建一个小的 jQuery 插件:

        $.fn.scrollDivToElement = function(childSel) {
            if (! this.length) return this;
        
            return this.each(function() {
                let parentEl = $(this);
                let childEl = parentEl.find(childSel);
        
                if (childEl.length > 0) {
                    parentEl.scrollTop(
                        parentEl.scrollTop() - parentEl.offset().top + childEl.offset().top - (parentEl.outerHeight() / 2) + (childEl.outerHeight() / 2)
                    );
                }
            });
        };
        

        用法:

        $('.scrollable-box').scrollDivToElement('.scrollable-item:eq(12)');
        

        说明:

        1. parentEl.scrollTop(...) 设置滚动条的当前垂直位置。

        2. parentEl.scrollTop() 获取滚动条的当前垂直位置。

        3. parentEl.offset().top 获取 parentEl 相对于文档的当前坐标。

        4. childEl.offset().top 获取 childEl 相对于文档的当前坐标。

        5. parentEl.outerHeight() / 2 将子元素的外部高度分成两半(因为我们希望它居中)。

        6. 使用时:

        $(parent).scrollDivToElement(child);

        parent 是可滚动的 div,它可以是 DOM 元素的字符串或 jQuery 对象。
        child 是您想要滚动到的任何子项,它可以是字符串或 DOM 元素的 jQuery 对象。

        Codepen demo

        【讨论】:

          【解决方案6】:

          我编写这两个函数是为了让我的生活更轻松:

          function scrollToTop(elem, parent, speed) {
              var scrollOffset = parent.scrollTop() + elem.offset().top;
              parent.animate({scrollTop:scrollOffset}, speed);
              // parent.scrollTop(scrollOffset, speed);
          }
          
          function scrollToCenter(elem, parent, speed) {
              var elOffset = elem.offset().top;
              var elHeight = elem.height();
              var parentViewTop = parent.offset().top;
              var parentHeight = parent.innerHeight();
              var offset;
          
              if (elHeight >= parentHeight) {
                  offset = elOffset;
              } else {
                  margin = (parentHeight - elHeight)/2;
                  offset = elOffset - margin;
              }
          
              var scrollOffset = parent.scrollTop() + offset - parentViewTop;
          
              parent.animate({scrollTop:scrollOffset}, speed);
              // parent.scrollTop(scrollOffset, speed);
          }
          

          并使用它们:

          scrollToTop($innerListItem, $parentDiv, 200);
          // or
          scrollToCenter($innerListItem, $parentDiv, 200);
          

          【讨论】:

          • elem.offset().top 正在从屏幕顶部计算。我想从父元素计算。我该怎么做?
          【解决方案7】:

          玩了很久,终于想到了这个:

              jQuery.fn.scrollTo = function (elem) {
                  var b = $(elem);
                  this.scrollTop(b.position().top + b.height() - this.height());
              };
          

          我这样称呼它

          $("#basketListGridHolder").scrollTo('tr[data-uid="' + basketID + '"]');
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-12-25
            • 1970-01-01
            • 2010-10-12
            相关资源
            最近更新 更多