Wie scrolle ich zu einem Element in einem überfüllten Div?

159

Ich habe 20 Listenelemente in einem Div, die jeweils nur 5 anzeigen können. Was ist ein guter Weg, um zu Punkt 10 und dann zu Punkt 20 zu scrollen? Ich kenne die Höhe aller Gegenstände.

Das scrollToPlugin macht das, aber seine Quelle ist nicht sehr einfach zu verstehen, ohne wirklich darauf einzugehen. Ich möchte dieses Plugin nicht verwenden.

Lassen Sie uns sagen , dass ich eine Funktion, die zwei Elemente nimmt $parentDiv, $innerListItemweder $innerListItem.offset().topnoch $innerListItem.positon().topgibt mir die richtige scrollTop für $ parentDiv.

mkoryak
quelle
Meine Antwort wurde aufgrund Ihres Updates entfernt. Aber glauben Sie mir, nachdem Sie zuvor dieselbe Einstellung hatten, gibt es viele Browser-Macken mit Position und Rändern usw. Das Plugin ist eine viel einfachere Route und weniger zeitaufwendig und nur 3k vor GZip.
Nick Craver
1
Verwenden Sie trotzdem das scrollTo-Plugin. Es ist nicht schwer. $("#container").scrollTo(target, duration, options). Ziel ist nur ein #anchor. Getan.
Ryan McGeary
Es scheint, dass es Wissen geben sollte, um dies ohne Plugin zu tun. morgen werde ich anfangen, die Quelle zu lesen
mkoryak
5
@mkoryak - Das Wissen ist da draußen, aber wenn Sie die Browser-Macken berücksichtigen, erhalten Sie im Grunde ... das .scrollTo-Plugin . Warum also das Rad immer wieder neu erfinden?
Nick Craver
1
IMHO, Sie werden wahrscheinlich genau die Teilmenge dessen erhalten, was Sie heute von .scrollTo benötigen . Aber in ein paar Monaten, während .scrollTo hat IE9, FF4 und Chrome 6 aktualisiert, Sie werden von vorne anfangen müssen ... 3k scheint wie ein sehr niedriger Preis , dies zu vermeiden.
Wim

Antworten:

236

Das $innerListItem.position().topist tatsächlich relativ zu dem .scrollTop()seines zuerst positionierten Vorfahren. Um den richtigen $parentDiv.scrollTop()Wert zu berechnen , müssen Sie zunächst sicherstellen, dass er $parentDivpositioniert ist. Wenn es noch keine explizite hat position, verwenden Sie position: relative. Die Elemente $innerListItemund alle ihre Vorfahren $parentDivmüssen keine explizite Position haben. Jetzt können Sie zu scrollen $innerListItemmit:

// 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);
Glenn Moss
quelle
152

Dies ist mein eigenes Plugin (positioniert das Element oben in der Liste. Speziell für overflow-y : auto. Funktioniert möglicherweise nicht mit overflow-x!):

HINWEIS : elemist der HTML-Selektor eines Elements, zu dem die Seite gescrollt wird. Alles , was von jQuery unterstützt, wie: #myid, div.myclass, $(jquery object), [dom - Objekt] usw.

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

Wenn Sie es nicht zum Animieren benötigen, verwenden Sie:

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

Wie benutzt man:

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

Hinweis: #innerItemKann überall drinnen sein #overflow_div. Es muss nicht unbedingt ein direktes Kind sein.

Getestet in Firefox (23) und Chrome (28).

Wenn Sie die gesamte Seite scrollen möchten, überprüfen Sie diese Frage .

Lepe
quelle
was ist elem?? du erklärst es überhaupt nicht.
vsync
Sie erhalten eine bessere Kilometerleistung / keinen Konflikt, wenn Sie stattdessen $ in der fn.scrollTo gegen jQuery tauschen
Barry Carlyon
Großer Fehler dabei, Sie enthalten nicht den Umfang: $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem, $(this)).offset().top);- Grüße
Luke Snowden
1
Wenn Sie einen oberen Rand zwischen der Seite und dem Element lassen möchten (was in einigen Fällen besser aussehen kann), subtrahieren Sie beispielsweise 10px wie : $(this).scrollTop() - $(this).offset().top + $(elem).offset().top - 10.
Lepe
Wenn Sie Positionsunterschiede zwischen Firefox und Chrome (oder anderen Browsern) haben, überprüfen Sie Ihren HTML-Code (siehe diesen Fehlerbericht )
Lepe
34

Ich habe die Antwort von Glenn Moss angepasst, um der Tatsache Rechnung zu tragen, dass der Überlauf div möglicherweise nicht oben auf der Seite steht.

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

Ich habe dies in einer Google Maps-Anwendung mit einer reaktionsfähigen Vorlage verwendet. Bei einer Auflösung> 800px befand sich die Liste auf der linken Seite der Karte. Bei einer Auflösung <800 befand sich die Liste unterhalb der Karte.

KPheasey
quelle
6

Die obigen Antworten positionieren das innere Element oben auf dem Überlaufelement, auch wenn es innerhalb des Überlaufelements sichtbar ist. Ich wollte das nicht, also habe ich es so geändert, dass die Bildlaufposition nicht geändert wird, wenn das Element angezeigt wird.

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;
};
Mike
quelle
Das hat mir geholfen !! Siehe stackoverflow.com/questions/48283932/…
Gen b.
1

Ich schreibe diese 2 Funktionen, um mein Leben leichter zu machen:

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

Und benutze sie:

scrollToTop($innerListItem, $parentDiv, 200);
// or
scrollToCenter($innerListItem, $parentDiv, 200);
Trank
quelle
elem.offset().topberechnet vom oberen Bildschirmrand aus. Ich möchte, dass das aus dem übergeordneten Element berechnet wird. Wie mache ich das ?
Santosh
0

Nachdem ich sehr lange damit gespielt hatte, kam ich auf Folgendes:

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

und ich nenne es so

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