找到第一个可滚动的父级

Jea*_*eri 39 javascript html5 css3

我有这种情况需要将元素滚动到视口中.问题是我不知道哪个元素是可滚动的.例如,在Portrait中,body是可滚动的,而在Landscape中它是另一个元素(并且有更多情况可以改变可滚动元素)

现在的问题是,给定一个需要滚动到视口中的元素,找到第一个可滚动父级的最佳方法是什么?

我在这里设置了一个演示.使用按钮,您可以在两种不同的情况之间切换

<div class="outer">
    <div class="inner">
        <div class="content"> 
            ...
            <span>Scroll me into view</span>
        </div>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

身体是可滚动的或 .outer

有什么建议 ?

Ste*_*rdo 43

只检查滚动条是否可见,如果没有查看父项.

function getScrollParent(node) {
  if (node == null) {
    return null;
  }

  if (node.scrollHeight > node.clientHeight) {
    return node;
  } else {
    return getScrollParent(node.parentNode);
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 根据@RustyToms和OP,我改写了这个:https://gist.github.com/twxia/bb20843c495a49644be6ea3804c0d775 (7认同)
  • 这很好,但不适用于溢出但仍无法滚动的节点.如果您添加[overflowY值]的检查(https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Determine_if_an_element_has_been_totally_scrolled),它似乎运行良好.`let overflowY = window.getComputedStyle(node).overflowY;``let isScrollable = overflowY!=='visible'&& overflowY!=='hidden';``if(isScrollable && node.scrollHeight> node.clientHeight){` (5认同)
  • 如果节点有一个 `inline` 父节点,`clientHeight` 将为 0,并且会在此处返回。最好忽略 `clientHeight` 为 0 的节点。 (2认同)
  • 又名 `while (node &amp;&amp; node.scrollHeight &lt;= node.clientHeight) node = node.parentNode;` (2认同)

Web*_*ner 37

这是cweston谈到的jQuery UI scrollParent方法的纯JS端口.我选择了这个而不是接受的答案的解决方案,如果没有内容溢出,它将找不到滚动父级.

与我的端口的一个区别是,如果没有找到具有CSS overflow属性的正确值的父级,则返回该<body>元素.相反,JQuery UI返回了该document对象.这是奇怪的,因为.scrollTop可以从<body>但不是从中检索到的值document.

function getScrollParent(element, includeHidden) {
    var style = getComputedStyle(element);
    var excludeStaticParent = style.position === "absolute";
    var overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/;

    if (style.position === "fixed") return document.body;
    for (var parent = element; (parent = parent.parentElement);) {
        style = getComputedStyle(parent);
        if (excludeStaticParent && style.position === "static") {
            continue;
        }
        if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) return parent;
    }

    return document.body;
}
Run Code Online (Sandbox Code Playgroud)

  • 返回 `document.scrollingElement` 来解决 @Skeets 点可能更好。也许这仍然因浏览器而异? (2认同)

ncu*_*ica 10

即使没有滚动条,大多数投票的答案在所有情况下scrollHeight > clientHeight都不起作用true

我找到了这个要点解决方案https://github.com/olahol/scrollparent.js/blob/master/scrollparent.js#L13

^ 全部归功于编写代码的https://github.com/olahol

将其重构为es6

export const getScrollParent = (node) => {
  const regex = /(auto|scroll)/;
  const parents = (_node, ps) => {
    if (_node.parentNode === null) { return ps; }
    return parents(_node.parentNode, ps.concat([_node]));
  };

  const style = (_node, prop) => getComputedStyle(_node, null).getPropertyValue(prop);
  const overflow = _node => style(_node, 'overflow') + style(_node, 'overflow-y') + style(_node, 'overflow-x');
  const scroll = _node => regex.test(overflow(_node));

  /* eslint-disable consistent-return */
  const scrollParent = (_node) => {
    if (!(_node instanceof HTMLElement || _node instanceof SVGElement)) {
      return;
    }

    const ps = parents(_node.parentNode, []);

    for (let i = 0; i < ps.length; i += 1) {
      if (scroll(ps[i])) {
        return ps[i];
      }
    }

    return document.scrollingElement || document.documentElement;
  };

  return scrollParent(node);
  /* eslint-enable consistent-return */
};
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它:

const $yourElement = document.querySelector('.your-class-or-selector');
getScrollParent($yourElement);
Run Code Online (Sandbox Code Playgroud)


cwe*_*ton 8

如果您使用的是jQuery UI,则可以使用该scrollParent方法.看看API源代码.

来自API:

.scrollParent():获取可滚动的最近的祖先元素

此方法不接受任何参数.此方法查找允许滚动的最近祖先.换句话说,该 .scrollParent()方法找到当前所选元素将在其中滚动的元素.

注意:此方法仅适用于包含一个元素的jQuery对象.

如果您没有使用jQuery UI但使用的是jQuery,那么还有其他独立的库提供类似的功能,例如:

jQuery的scrollparent

  • 我在这里将其移植到香草JS:http://stackoverflow.com/questions/35939886/find-first-scrollable-parent#42543908 (2认同)