Jak przewinąć do elementu w przepełnionym elemencie Div?

159

Mam 20 elementów listy wewnątrz elementu div, które mogą wyświetlać tylko 5 na raz. Jaki jest dobry sposób na przewinięcie do punktu nr 10, a następnie punktu nr 20? Znam wysokość wszystkich przedmiotów.

scrollToPlugin to robi, ale jego źródłem nie jest super łatwy do zrozumienia bez naprawdę się do niego. Nie chcę używać tej wtyczki.

Powiedzmy, że mam funkcję, która trwa od 2 elementów $parentDiv, $innerListItemani $innerListItem.offset().topteż nie $innerListItem.positon().topdaje mi poprawną scrollTop dla $ parentDiv.

mkoryak
źródło
Usunąłem moją odpowiedź z powodu Twojej aktualizacji. Ale zaufaj mi, mając takie samo podejście wcześniej, istnieje wiele dziwactw przeglądarki z pozycją i marginesami itp ... wtyczka jest znacznie prostszą trasą i mniej czasochłonną, i tylko 3k przed GZip.
Nick Craver
1
Mimo to użyj wtyczki scrollTo. To nie jest trudne. $("#container").scrollTo(target, duration, options). Cel to po prostu #anchor. Gotowe.
Ryan McGeary
wydaje się, że powinna istnieć wiedza umożliwiająca zrobienie tego bez wtyczki. jutro źle zacznę czytać źródło
mkoryak
5
@mkoryak - Wiedza jest tam, ale kiedy weźmiesz pod uwagę dziwactwa przeglądarki, w zasadzie otrzymujesz ... wtyczkę .scrollTo , więc po co ciągle wymyślać koło?
Nick Craver
1
IMHO, będziesz prawdopodobnie skończyć z dokładnym podzbioru co trzeba z .scrollTo dzisiaj . Ale za kilka miesięcy, podczas gdy .scrollTo został zaktualizowany do IE9, FF4 i Chrome 6, będziesz musiał zacząć od nowa ... 3k wydaje się bardzo niską ceną, aby tego uniknąć.
Wim

Odpowiedzi:

236

W $innerListItem.position().toprzeczywistości jest względny w stosunku do .scrollTop()swojego pierwszego przodka. Tak więc sposobem obliczenia prawidłowej $parentDiv.scrollTop()wartości jest rozpoczęcie od upewnienia się, że $parentDivjest ustawiona. Jeśli nie ma jeszcze wyraźnego position, użyj position: relative. Elementy $innerListItemi wszyscy jego przodkowie nie $parentDivmuszą mieć wyraźnej pozycji. Teraz możesz przewinąć do za $innerListItempomocą:

// 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
źródło
152

To jest moja własna wtyczka (umieści element na górze listy. Specjalnie dla overflow-y : auto. Może nie działać overflow-x!):

UWAGA : elemto selektor HTML elementu, do którego będzie przewijana strona. Wszystko poparte jQuery, takich jak: #myid, div.myclass, $(jquery object), [dom przedmiot], etc.

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

Jeśli nie potrzebujesz animacji, użyj:

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

Jak używać:

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

Uwaga: #innerItemmoże znajdować się w dowolnym miejscu w środku #overflow_div. Tak naprawdę nie musi to być bezpośrednie dziecko.

Przetestowano w przeglądarkach Firefox (23) i Chrome (28).

Jeśli chcesz przewinąć całą stronę, sprawdź to pytanie .

lepe
źródło
co to jest elem?? w ogóle tego nie wyjaśniasz.
vsync
Uzyskasz lepszy przebieg / brak konfliktów, jeśli zamiast tego zamienisz $ w fn.scrollTo na jQuery
Barry Carlyon
Wielka wada w tym, że nie masz zakresu: $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem, $(this)).offset().top);- pozdrawiam
Luke Snowden
1
Jeśli chcesz zostawić pewien margines górny między strony i element (co może wyglądać lepiej w niektórych przypadkach), odejmowanie, np 10px, takich jak: $(this).scrollTop() - $(this).offset().top + $(elem).offset().top - 10.
lepe
Jeśli masz różnice pozycji między Firefoksem i Chrome (lub innymi przeglądarkami), sprawdź swój kod HTML (zobacz ten raport o błędzie )
lepe
34

Dostosowałem odpowiedź Glenna Mossa, aby uwzględnić fakt, że element div przepełnienia może nie znajdować się na górze strony.

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

Używałem tego w aplikacji Google Maps z responsywnym szablonem. Przy rozdzielczości> 800 pikseli lista znajdowała się po lewej stronie mapy. Przy rozdzielczości <800 lista znajdowała się poniżej mapy.

KPheasey
źródło
6

Powyższe odpowiedzi spowodują umieszczenie elementu wewnętrznego na górze elementu przepełnienia, nawet jeśli jest on widoczny wewnątrz elementu przepełnienia. Nie chciałem tego, więc zmodyfikowałem go, aby nie zmieniać pozycji przewijania, jeśli element jest widoczny.

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;
};
mikrofon
źródło
To mi pomogło !! Zobacz stackoverflow.com/questions/48283932/…
gen b.
1

Piszę te 2 funkcje, aby ułatwić sobie życie:

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

I użyj ich:

scrollToTop($innerListItem, $parentDiv, 200);
// or
scrollToCenter($innerListItem, $parentDiv, 200);
trank
źródło
elem.offset().topoblicza od góry ekranu. Chcę, aby obliczyć z elementu nadrzędnego. W jaki sposób mogę to zrobić ?
Santosh
0

Po zabawie przez bardzo długi czas wymyśliłem to:

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

i tak to nazywam

$("#basketListGridHolder").scrollTo('tr[data-uid="' + basketID + '"]');
Bruce Reeves
źródło