Jak sprawić, by element przewinął się do widoku, używając jQuery?

169

Mam dokument HTML z obrazami w formacie siatki przy użyciu <ul><li><img.... Okno przeglądarki umożliwia przewijanie zarówno w pionie, jak iw poziomie.

Pytanie: W <img>jaki sposób po kliknięciu obrazu mogę przewinąć cały dokument do pozycji, w której znajduje się właśnie kliknięty obraz top:20px; left:20px?

Przeglądałem tutaj podobne posty ... chociaż jestem całkiem nowy w JavaScript i chcę zrozumieć, jak to się robi.

Nasir
źródło

Odpowiedzi:

192

Ponieważ chcesz wiedzieć, jak to działa, wyjaśnię to krok po kroku.

Najpierw chcesz powiązać funkcję jako moduł obsługi kliknięcia obrazu:

$('#someImage').click(function () {
    // Code to do scrolling happens here
});

Spowoduje to zastosowanie modułu obsługi kliknięcia do obrazu z rozszerzeniem id="someImage". Jeśli chcesz to zrobić do wszystkich zdjęć, wymień '#someImage'się 'img'.

Teraz rzeczywisty kod przewijania:

  1. Uzyskaj przesunięcia obrazu (względem dokumentu):

    var offset = $(this).offset(); // Contains .top and .left
  2. Odejmij 20 od topi left:

    offset.left -= 20;
    offset.top -= 20;
  3. Teraz animuj właściwości CSS scroll-top i scroll-left w <body>i <html>:

    $('html, body').animate({
        scrollTop: offset.top,
        scrollLeft: offset.left
    });
David Tang
źródło
3
Działa to tylko w przypadku prostych układów. Nie obsługuje wszystkich przypadków tak, jak .scrollIntoViewrobi to metoda W3C , gdy elementy są zagnieżdżone w wielu przepełnionych kontenerach.
natevw
2
dlaczego wynaleźć koło na nowo? Element.scrollIntoView(): developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
Serge
@Serge, ponieważ jest to robocza wersja robocza, która nie została zaimplementowana we wszystkich przeglądarkach
John Smith
@JohnSmith proszę uważnie przeczytać link, który zamieściłem, w sekcji „Zgodność z przeglądarkami”, zobaczysz, że żadna przeglądarka nie obsługujescrollIntoView
Serge
@Serge Przepraszam za to, nie zdawałem sobie sprawy, że był tam również scrollIntoViewOption (który nie jest wystarczająco szeroki). Myślę, że to wystarczy.
John Smith
377

Jest wywoływana metoda DOM scrollIntoView, obsługiwana przez wszystkie główne przeglądarki, która wyrówna element z górną / lewą krawędzią widoku (lub tak blisko, jak to możliwe).

$("#myImage")[0].scrollIntoView();

W obsługiwanych przeglądarkach możesz podać opcje:

$("#myImage")[0].scrollIntoView({
    behavior: "smooth", // or "auto" or "instant"
    block: "start" // or "end"
});

Alternatywnie, jeśli wszystkie elementy mają unikalne identyfikatory, możesz po prostu zmienić hashwłaściwość locationobiektu na obsługę przycisków Wstecz / Dalej:

$(document).delegate("img", function (e) {
    if (e.target.id)
        window.location.hash = e.target.id;
});

Następnie dostosuj scrollTop/ scrollLeftproperties o -20:

document.body.scrollLeft -= 20;
document.body.scrollTop -= 20;
Andy E.
źródło
2
Dziękuję Ci! 5 innych artykułów SO i doskonale to zrobiłeś. Moim przypadkiem użycia był kontener w oknie dialogowym ładowania początkowego, który należy przewinąć do widoku.
Stephen Patten
10
Uwaga: $("#myImage")[0].scrollIntoView(false);wyrówna element na dole okna.
Filip
1
Uwaga: „płynne” zachowanie nie jest powszechnie obsługiwane i scrollIntoViewmoże być mylące dla użytkowników bez jakiejś animacji.
Cody Duval
1
@JohnHenckel: to niepoprawne, nawet IE 5.5 miał scrollIntoViewparametr boolowski. Spróbuję później wysłać prośbę o ściągnięcie dla caniuse.com.
Andy E
1
Uwaga: używając Chrome, nie mogłem przewijać <td>elementów do widoku, zamiast tego musiałem przewijać ich rodzica ( <tr>) i zadziałało.
CrazyTim
13

Najprostsze rozwiązanie, jakie widziałem

var offset = $("#target-element").offset();
$('html, body').animate({
    scrollTop: offset.top,
    scrollLeft: offset.left
}, 1000);

Samouczek tutaj

Matt Watson
źródło
Ryzykując, że będzie to mniej proste, zredagowałem to, aby obsługiwać również przewijanie w poziomie.
jpaugh
7

Istnieją metody przewijania elementu bezpośrednio do widoku, ale jeśli chcesz przewinąć do punktu względem elementu, musisz to zrobić ręcznie:

W module obsługi kliknięcia uzyskaj położenie elementu względem dokumentu, odejmij 20i użyj window.scrollTo:

var pos = $(this).offset();
var top = pos.top - 20;
var left = pos.left - 20;
window.scrollTo((left < 0 ? 0 : left), (top < 0 ? 0 : top));
Felix Kling
źródło
7

Spójrz na wtyczkę jQuery.scrollTo . Oto demo .

Ta wtyczka ma wiele opcji, które wykraczają poza to, co natywne scrollIntoView oferuje . Na przykład możesz ustawić przewijanie na płynne, a następnie ustawić oddzwanianie po zakończeniu przewijania.

Możesz także rzucić okiem na wszystkie wtyczki JQuery z tagiem „scroll” .

Rob Stevenson-Leggett
źródło
Otrzymywałem różne przesunięcia / pozycje w każdej przeglądarce w moim przypadku, a ta wtyczka pomogła mi to naprawić! dzięki!
LaurelB,
4

Oto szybka wtyczka jQuery do ładnego mapowania wbudowanych funkcji przeglądarki:

$.fn.ensureVisible = function () { $(this).each(function () { $(this)[0].scrollIntoView(); }); };

...

$('.my-elements').ensureVisible();
Obrabować
źródło
3

Po próbach i błędach wymyśliłem tę funkcję, działa też z iframe.

function bringElIntoView(el) {    
    var elOffset = el.offset();
    var $window = $(window);
    var windowScrollBottom = $window.scrollTop() + $window.height();
    var scrollToPos = -1;
    if (elOffset.top < $window.scrollTop()) // element is hidden in the top
        scrollToPos = elOffset.top;
    else if (elOffset.top + el.height() > windowScrollBottom) // element is hidden in the bottom
        scrollToPos = $window.scrollTop() + (elOffset.top + el.height() - windowScrollBottom);
    if (scrollToPos !== -1)
        $('html, body').animate({ scrollTop: scrollToPos });
}
Tone Škoda
źródło
2

Tylko wskazówka. Działa tylko w przeglądarce Firefox

Element.scrollIntoView ();

student wp
źródło
4
Działa to dla wszystkich przeglądarek z parametrem boolowskim lub bez parametrów. Mniej obsługiwany jest tylko bardziej zaawansowany parametr obiektu.
Risord
według developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView jest ogólny brak obsługi tego przeglądarki
lfender6445
Teraz jest wystarczająco dobrze obsługiwany tylko Opera Mini: caniuse.com/#search=scrollIntoView
John Magnolia
Jest do tego wiele bardzo lekkich wypełniaczy.
Martin James
1

Mój interfejs użytkownika zawiera przewijaną w pionie listę kciuków na pasku miniatur. Celem było umieszczenie bieżącego kciuka na środku paska. Zacząłem od zatwierdzonej odpowiedzi, ale stwierdziłem, że było kilka poprawek, aby naprawdę wycentrować bieżący kciuk. mam nadzieję, że to pomoże komuś innemu.

narzut:

<ul id='thumbbar'>
    <li id='thumbbar-123'></li>
    <li id='thumbbar-124'></li>
    <li id='thumbbar-125'></li>
</ul>

jQuery:

// scroll the current thumb bar thumb into view
heightbar   = $('#thumbbar').height();
heightthumb = $('#thumbbar-' + pageid).height();
offsetbar   = $('#thumbbar').scrollTop();


$('#thumbbar').animate({
    scrollTop: offsetthumb.top - heightbar / 2 - offsetbar - 20
});
xeo
źródło
0

Proste 2 kroki przewijania w dół do końca lub do dołu.

Krok 1: uzyskaj pełną wysokość przewijalnego (konwersacji) div.

Krok 2: zastosuj scrollTop do tego przewijalnego elementu div (konwersacji), używając wartości uzyskanej w kroku 1.

var fullHeight = $('#conversation')[0].scrollHeight;

$('#conversation').scrollTop(fullHeight);

Powyższe kroki należy zastosować dla każdego dodatku do div konwersacji.

Shiva Kumar P.
źródło
0

Po próbie znalezienia rozwiązania, które poradziłoby sobie z każdą sytuacją (opcje animacji zwoju, wypełniania wokół obiektu po przewinięciu do widoku, działa nawet w niejasnych okolicznościach, takich jak iframe), w końcu napisałem własne rozwiązanie tego problemu. Ponieważ wydaje się działać, gdy wiele innych rozwiązań zawiodło, pomyślałem, że podzielę się tym:

function scrollIntoViewIfNeeded($target, options) {

    var options = options ? options : {},
    $win = $($target[0].ownerDocument.defaultView), //get the window object of the $target, don't use "window" because the element could possibly be in a different iframe than the one calling the function
    $container = options.$container ? options.$container : $win,        
    padding = options.padding ? options.padding : 20,
    elemTop = $target.offset().top,
    elemHeight = $target.outerHeight(),
    containerTop = $container.scrollTop(),
    //Everything past this point is used only to get the container's visible height, which is needed to do this accurately
    containerHeight = $container.outerHeight(),
    winTop = $win.scrollTop(),
    winBot = winTop + $win.height(),
    containerVisibleTop = containerTop < winTop ? winTop : containerTop,
    containerVisibleBottom = containerTop + containerHeight > winBot ? winBot : containerTop + containerHeight,
    containerVisibleHeight = containerVisibleBottom - containerVisibleTop;

    if (elemTop < containerTop) {
        //scroll up
        if (options.instant) {
            $container.scrollTop(elemTop - padding);
        } else {
            $container.animate({scrollTop: elemTop - padding}, options.animationOptions);
        }
    } else if (elemTop + elemHeight > containerTop + containerVisibleHeight) {
        //scroll down
        if (options.instant) {
            $container.scrollTop(elemTop + elemHeight - containerVisibleHeight + padding);
        } else {
            $container.animate({scrollTop: elemTop + elemHeight - containerVisibleHeight + padding}, options.animationOptions);
        }
    }
}

$target jest obiektem jQuery zawierającym obiekt, który chcesz przewinąć do widoku w razie potrzeby.

options (opcjonalnie) może zawierać następujące opcje przekazane w obiekcie:

options.$container- obiekt jQuery wskazujący na zawierający element $ target (innymi słowy, element w dom z suwakami). Domyślnie jest to okno, które zawiera element $ target i jest wystarczająco inteligentne, aby wybrać okno iframe. Pamiętaj o umieszczeniu znaku $ w nazwie właściwości.

options.padding- wypełnienie w pikselach, które ma być dodane powyżej lub poniżej obiektu, gdy jest przewijany do widoku. W ten sposób nie znajduje się bezpośrednio przy krawędzi okna. Domyślnie 20.

options.instant- jeśli ustawione na true, jQuery animate nie będzie używane, a przewijanie natychmiast wyskoczy do właściwej lokalizacji. Domyślnie false.

options.animationOptions - wszelkie opcje jQuery, które chcesz przekazać do funkcji animacji jQuery (patrz http://api.jquery.com/animate/ ). Dzięki temu możesz zmienić czas trwania animacji lub zlecić wykonanie funkcji zwrotnej po zakończeniu przewijania. Działa to tylko wtedy, gdy options.instantma wartość false. Jeśli potrzebujesz natychmiastowej animacji, ale z wywołaniem zwrotnym, ustaw options.animationOptions.duration = 0zamiast używać options.instant = true.

dallin
źródło