Trouver le premier parent défilant

J'ai cette situation dans laquelle je dois faire défiler un élément dans la fenêtre. Le problème est que je ne sais pas quel élément est défilant. Par exemple, dans Portrait, le corps est défilant et dans Paysage c'est un autre élément (et il y a plus de situation qui change l'élément défilant)

Maintenant, la question, étant donné un élément qui doit être défilé dans la fenêtre, Quelle est la meilleure façon de trouver son premier parent défilant ?

J'ai configuré une démo ici. Avec le bouton, vous pouvez basculer entre deux situations différentes

<div class="outer">
    <div class="inner">
        <div class="content"> 
            ...
            <span>Scroll me into view</span>
        </div>
    </div>
</div>

Le corps est défilant ou .outer

Des suggestions ?

23
demandé sur Jeanluca Scaljeri 2016-03-11 15:06:54

5 réponses

Vérifiez simplement si la barre de défilement est visible, sinon regardez le parent.

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

  if (node.scrollHeight > node.clientHeight) {
    return node;
  } else {
    return getScrollParent(node.parentNode);
  }
}
29
répondu Stefano Nardo 2017-09-07 14:28:07

C'est un port js pur de la méthode jQuery UI scrollParent dont cweston a parlé. Je suis allé avec ceci plutôt que la solution de la réponse acceptée qui ne trouvera pas le parent de défilement s'il n'y a pas encore de débordement de contenu.

La seule différence avec mon port est que, si aucun parent n'est trouvé avec la bonne valeur pour la propriété CSS overflow, je retourne l'élément <body>. JQuery UI, à la place retourné l'objet document. Ceci est impair car des valeurs telles que .scrollTop peuvent être récupérées à partir du <body> mais pas le 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;
}
23
répondu Web_Designer 2017-05-23 10:31:12

Si vous utilisez L'interface utilisateur jQuery, vous pouvez utiliser la méthode scrollParent. Consultez l'API ou la source .

À Partir de l'API:

.scrollParent(): Obtenez l'élément ancêtre le plus proche qui est scrollable

Cette méthode n'accepte aucun argument. Cette méthode trouve l'ancêtre le plus proche qui permet le défilement. En d'autres termes, l' .scrollParent() méthode trouve l'élément actuellement sélectionné l'élément défilera à l'intérieur.

Note: Cette méthode ne fonctionne que sur les objets jQuery contenant un élément.

Si vous n'utilisez pas L'interface utilisateur jQuery mais que vous utilisez jQuery, il existe d'autres bibliothèques indépendantes offrant des fonctionnalités similaires, telles que:

Jquery-scrollparent

8
répondu cweston 2017-03-01 22:53:20

La réponse avec la plupart des votes ne fonctionne pas dans tous les cas scrollHeight > clientHeight qui peut être true même si vous n'avez pas de barre de défilement, j'ai trouvé cette solution essentielle https://github.com/olahol/scrollparent.js/blob/master/scrollparent.js#L13

^ crédit total à https://github.com/olahol qui a écrit le code.

Je l'ai refactorisé à 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 */
};

Vous pouvez l'utiliser comme:

const $yourElement = document.querySelector('.your-class-or-selector');
getScrollParent($yourElement);
2
répondu ncubica 2018-03-09 04:38:11

Je pense que tu veux ça.

$('button').click(function() {
  $("body").addClass("body");
  $('.outer').toggleClass('scroller');
  check($(".content"));
});

function check(el) {
  var overflowY = el.css("overflow-y");  
  if (overflowY == "scroll") {
    alert(el.attr("class") + " has");
  } else {
    if(el.parent().length > 0)
   	  check(el.parent());
    else 
      return false;
  }
}
body {
  height: 450px;
  overflow-y: scroll;
}

div.inner {
  width: 200px;
  height: 400px;
  border: 1px solid #000;
}

div.outer {
  width: 200px;
  height: 200px;
}

div.outer.scroller {
  overflow-y: scroll;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>
  toggle
</button>
<div class="outer">
  <div class="inner">
    <div class="content">
      "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
      in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." adipiscing elit, sed do eiusmod tempor incididunt ut
      labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur
      sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
    </div>
  </div>
</div>
1
répondu NiZa 2016-03-11 12:29:51