web-dev-qa-db-fra.com

Trouver le premier parent à défilement

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 scrollable. Par exemple, dans Portrait, le corps peut défiler et dans Paysage, il s'agit d'un autre élément (et il existe d'autres situations qui modifient l'élément défilable).

Maintenant la question, étant donné un élément qui doit être fait défiler dans la fenêtre, quel est le meilleur moyen de trouver son premier parent à défilement?

J'ai mis en place 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 scrollable ou .outer

Aucune suggestion ?

25
Jeanluca Scaljeri

Il suffit de vérifier si la barre de défilement est visible, sinon cherchez le parent. 

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

  if (node.scrollHeight > node.clientHeight) {
    return node;
  } else {
    return getScrollParent(node.parentNode);
  }
}
34
Stefano Nardo

Il s'agit d'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 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, a retourné l’objet document. C'est étrange, car des valeurs comme .scrollTop peuvent être extraites du <body> mais pas de la 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;
}
27
Web_Designer

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

Depuis l'API:

.scrollParent(): Récupère l'élément ancêtre le plus proche qui peut défiler

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, le La méthode .scrollParent() trouve l'élément qui a été sélectionné l'élément défilera à l'intérieur.

Remarque: cette méthode ne fonctionne que sur les objets jQuery contenant un seul élément.

Si vous n'utilisez pas l'interface utilisateur de jQuery, mais plutôt jQuery, d'autres bibliothèques indépendantes offrant des fonctionnalités similaires, telles que:

jquery-scrollparent

8
cweston

la réponse avec la plupart des votes ne fonctionne pas dans tous les cas scrollHeight > clientHeight cela peut être true même si je n'ai pas de barre de défilement, j'ai trouvé cette solution Gist 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é en 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
ncubica

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
NiZa

À l'aide des outils de développement de Google Chrome, inspectez la page lorsque vous avez fait défiler partiellement la page, puis sélectionnez le nœud DOM qui, selon vous, pourrait être celui qui est en train de défiler. Ensuite, ouvrez la console (appuyez sur Echap depuis l’onglet Eléments des outils de développement) et tapez $0.scrollTop. Cela affichera la position de défilement actuelle de cet élément. Si ce n'est pas 0, alors vous saurez que c'est l'élément qui défile.

0
Drew2

de @ Stefano Nardo répondre je réécris cela. Ça fonctionne bien pour moi. 

function getScrollParent(node){
   if(!node) return null;
   else if (node.scrollTop>0) return node;
   return getScrollParent(node.parentNode) || document.documentElement;
} 
0
dagalti

S'appuyant sur la réponse de @ Web_Designer ,

Si vous passez le jQuery object pour cet élément et obtenez l'erreur suivante,

Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'

Ensuite, essayez de ne transmettre que le Dom Node element qui est situé au niveau de la clé de tableau 0 si l'élément est un élément unique. Par exemple. 

getScrollParent(jQuery("#" + formid)[0])
0
Mohd Abdul Mujib