Comment faire défiler jusqu'à un élément dans une Div débordée?


159

J'ai 20 éléments de liste à l'intérieur d'un div qui ne peuvent en afficher que 5 à la fois. Quelle est la bonne façon de faire défiler jusqu'à l'élément n ° 10, puis l'élément n ° 20? Je connais la hauteur de tous les objets.

Le scrollToplugin fait cela, mais sa source n'est pas super facile à comprendre sans vraiment y entrer. Je ne veux pas utiliser ce plugin.

Disons que j'ai une fonction qui prend 2 éléments $parentDiv, $innerListItemni $innerListItem.offset().topne $innerListItem.positon().topme donne le scrollTop correct pour $ parentDiv.


J'ai supprimé ma réponse en raison de votre mise à jour. Mais croyez-moi, ayant eu cette même attitude avant, il y a beaucoup de bizarreries de navigateur avec la position et les marges, etc ... le plugin est une route beaucoup plus simple et moins longue, et seulement 3k avant GZip.
— Nick Craver

1
Utilisez quand même le plugin scrollTo. Ce n'est pas difficile. $("#container").scrollTo(target, duration, options). La cible est juste un #anchor. Terminé.
— Ryan McGeary

il semble qu'il devrait y avoir des connaissances pour faire cela sans plugin. demain malade commencer à lire la source
— mkoryak

5
@mkoryak - Les connaissances sont là, mais lorsque vous tenez compte des bizarreries du navigateur, vous vous retrouvez essentiellement avec ... le plugin .scrollTo , alors pourquoi réinventer la roue tout le temps?
— Nick Craver

1
IMHO, vous vous retrouverez probablement avec le sous-ensemble exact de ce dont vous avez besoin de .scrollTo aujourd'hui . Mais dans quelques mois, alors que .scrollTo a été mis à jour vers IE9, FF4 et Chrome 6, vous devrez recommencer ... 3k semble être un prix très bas pour éviter cela.
— Wim

Réponses:


236

Le $innerListItem.position().topest en fait relatif au .scrollTop()de son premier ancêtre positionné. Donc, la façon de calculer la $parentDiv.scrollTop()valeur correcte est de commencer par s'assurer qu'elle $parentDivest positionnée. S'il n'a pas déjà d'explicite position, utilisez position: relative. Les éléments $innerListItemet tous ses ancêtres jusqu'à ne $parentDivdoivent avoir aucune position explicite. Vous pouvez maintenant faire défiler jusqu'à $innerListItemavec:

// 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);

152

Ceci est mon propre plugin (positionnera l'élément en haut de la liste. Spécialement pour overflow-y : auto. Peut ne pas fonctionner avec overflow-x!):

REMARQUE : elemest le sélecteur HTML d'un élément vers lequel défilera la page. Tout ce que soutenu par jQuery, comme: #myid, div.myclass, $(jquery object), [objet dom], etc.

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

Si vous n'avez pas besoin de l'animer, utilisez:

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

Comment utiliser:

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

Remarque: #innerItempeut être n'importe où à l'intérieur #overflow_div. Ce n'est pas vraiment un enfant direct.

Testé dans Firefox (23) et Chrome (28).

Si vous souhaitez faire défiler toute la page, cochez cette question .


qu'est ce que c'est elem?? vous ne l'expliquez pas du tout.
— vsync

Vous obtenez un meilleur kilométrage / non-conflit si vous échangez $ dans le fn.scrollTo vers jQuery à la place
— Barry Carlyon

Gros défaut avec ça, vous ne contenant pas la portée: $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem, $(this)).offset().top);- salutations
— Luke Snowden

1
Si vous voulez laisser une certaine marge supérieure entre la page et l'élément (qui peut mieux dans certains cas), soustraire, par exemple, 10px, comme: $(this).scrollTop() - $(this).offset().top + $(elem).offset().top - 10.
— lepe

Si vous rencontrez des différences de position entre Firefox et Chrome (ou d'autres navigateurs), vérifiez votre code html (voir ce rapport de bogue )
— lepe

34

J'ai ajusté la réponse de Glenn Moss pour tenir compte du fait que la division de débordement pourrait ne pas être en haut de la page.

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

J'utilisais ceci sur une application google maps avec un modèle réactif. Avec une résolution> 800px, la liste se trouvait sur le côté gauche de la carte. Pour une résolution <800, la liste était sous la carte.


6

Les réponses ci-dessus positionneront l'élément interne en haut de l'élément de débordement même s'il est visible à l'intérieur de l'élément de débordement. Je ne voulais pas cela, alors je l'ai modifié pour ne pas changer la position de défilement si l'élément est en vue.

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;
};


1

J'écris ces 2 fonctions pour me faciliter la vie:

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);
}

Et utilisez-les:

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

elem.offset().topcalcule à partir du haut de l'écran. Je veux que calculer à partir de l'élément parent. Comment je fais ça ?
— Santosh

0

Après avoir joué avec pendant très longtemps, voici ce que j'ai trouvé:

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

et je l'appelle comme ça

$("#basketListGridHolder").scrollTo('tr[data-uid="' + basketID + '"]');
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.