ScrollIntoView () powoduje przesunięcie całej strony


110

Używam ScrollIntoView (), aby przewinąć podświetlony element na liście do widoku. Kiedy przewijam w dół, ScrollIntoView (false) działa idealnie. Ale kiedy przewijam w górę, ScrollIntoView (true) powoduje, że cała strona lekko się porusza, co moim zdaniem jest zamierzone. Czy istnieje sposób na uniknięcie przesunięcia całej strony podczas korzystania z ScrollIntoView (true)?

Oto struktura mojej strony -

#listOfDivs {
  position:fixed;
  top:100px;
  width: 300px;
  height: 300px;
  overflow-y: scroll;
}

<div="container">
    <div="content"> 
         <div id="listOfDivs"> 
             <div id="item1"> </div>
             <div id="item2"> </div>
             <div id="itemn"> </div>
         </div>
    </div>
</div>

listOfDivs pochodzi z połączenia AJAX. Korzystanie z mobilnego safari.

Z góry dziękuję za pomoc!


1
Czy możesz dostarczyć JSFiddle, abyśmy mogli dokładnie zobaczyć, na czym polega problem?
Robert Koritnik

Odpowiedzi:


120

Możesz użyć scrollTopzamiast scrollIntoView():

var target = document.getElementById("target");
target.parentNode.scrollTop = target.offsetTop;

jsFiddle: http://jsfiddle.net/LEqjm/

Jeśli istnieje więcej niż jeden przewijalny element, który chcesz przewinąć, musisz zmienić scrollTopkażdy z nich indywidualnie, na podstawie offsetTops elementów pośredniczących. Powinno to zapewnić precyzyjną kontrolę, aby uniknąć problemu, który masz.

EDYCJA: offsetTop niekoniecznie musi być względny w stosunku do elementu nadrzędnego - jest względem pierwszego umieszczonego elementu nadrzędnego. Jeśli element nadrzędny nie jest pozycjonowany (względny, bezwzględny lub stały), może zajść potrzeba zmiany drugiej linii na:

target.parentNode.scrollTop = target.offsetTop - target.parentNode.offsetTop;

4
FYI, to działa tylko wtedy, gdy rodzic jest na górze strony. Prawdopodobnie powinieneś to zrobićtarget.parentNode.scrollTop = target.offsetTop - target.parentNode.offsetTop
Phil

2
offsetTop jest względne do najbliższego położonego rodzica, więc jeśli węzeł nadrzędny ma position: relative, nie należy odejmować jego przesunięcia. Ale w większości przypadków masz rację.
Brilliand

2
Oto skrzypce js: jsfiddle.net/LEqjm/258, które pokazuje również niewłaściwe zachowanie ScrollIntoView.
Rafi

1
@Brilliand dziękuję za pomysł position: relativena prent div: to naprawdę rozwiązuje problem
Alex Zhukovskiy

Działa na chrome, ale przewija się trochę bardziej w IE, co ukrywa zawartość tekstową od góry. Jakiekolwiek rozwiązanie @Phil, z góry
dziękuję

128

Naprawiono to za pomocą:

element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' })

zobacz: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView


1
Dzięki, to zadziałało. Nie udało mi się zrozumieć użycia bloku i jego wartości, kiedy go czytam. Teraz, gdy rozwiązał problem, wiem, co robi
Pavan,

3
Co oznacza „najbliższy”? EDYCJA: znalazłem odpowiedź tutaj: stackoverflow.com/a/48635751/628418
Sammi

To rozwiązało mój problem. Widziałem to od jakiegoś czasu w naszej aplikacji internetowej, ale trudno było zablokować to powtórzenie. Po dodaniu nowej funkcji zdarzało się to za każdym razem i mogłem prześledzić to do tego wywołania, w którym brakowało block : 'nearest'parametru.
roskelld

Gdyby tylko zdefiniowali, co oznaczają wartości bloków… początek i najbliższe… to wszystko metodą prób i błędów.
Bae,

Działa z Chrome, ale nie z Edge dla mnie.
Michael

13
var el = document.querySelector("yourElement");
window.scroll({top: el.offsetTop, behavior: 'smooth'});

lub możesz skorzystaćtop: el['offsetTop']
Junior Mayhé

To działa najlepiej dla mnie. Ale nadal jest trochę błędny w Firefoksie - czasami zatrzymuje się częściowo na elemencie. Drobne na krawędzi i chromowane.
Mark

10

Ja też miałem ten problem i spędziłem wiele godzin próbując sobie z nim poradzić. Mam nadzieję, że moje postanowienie może nadal pomóc niektórym ludziom.

Moja poprawka zakończyła się następująco:

  • Chrome: zmiana .scrollIntoView()na .scrollIntoView({block: 'nearest'})(dzięki @jfrohn).
  • W przeglądarce Firefox: zastosuj overflow: -moz-hidden-unscrollable;do elementu kontenera, który się przesuwa.
  • Nie testowano w innych przeglądarkach.

9

Pobaw się scrollIntoViewIfNeeded()... upewnij się, że jest obsługiwany przez przeglądarkę.


1
Nie wiedziałem, że to jest rzecz. Jest polyfill
mpen

W dokumencie wspomniano, że jest niestandardowy, ale działa dobrze. powinniśmy go użyć?
Shyam Kumar

8

Dodałem sposób wyświetlania zachowania importera ScrollIntoView - http://jsfiddle.net/LEqjm/258/ [powinien to być komentarz, ale nie mam wystarczającej reputacji]

$("ul").click(function() {
    var target = document.getElementById("target");
if ($('#scrollTop').attr('checked')) {
    target.parentNode.scrollTop = target.offsetTop;    
} else {
        target.scrollIntoView(!0);
}
});

7
To nie jest pytanie jQuery.
seangates

6

Wtyczka jQuery scrollintoview()zwiększa użyteczność

Zamiast domyślnej implementacji DOM możesz użyć wtyczki, która animuje ruch i nie ma żadnych niepożądanych efektów. Oto najprostszy sposób używania go z ustawieniami domyślnymi:

$("yourTargetLiSelector").scrollintoview();

W każdym razie przejdź do tego wpisu na blogu, w którym możesz przeczytać wszystkie szczegóły i ostatecznie przekieruje Cię do kodu źródłowego wtyczki GitHub .

Ta wtyczka automatycznie wyszukuje najbliższy przewijalny element nadrzędny i przewija go tak, że wybrany element znajduje się w widocznym miejscu. Jeśli element jest już w porcie widoku, to oczywiście nic nie robi.


19
@Brilliand: To oczywiście prawda, ale to nie znaczy, że go nie używają lub niechętnie go używają. Wszystko, co robię, to zapewnienie alternatywy. Jest na OP, aby zdecydować, czy to ścieżka, którą wybiorą, czy nie. Może w ogóle nigdy nie rozważali używania jQuery.
Robert Koritnik

Ten OP nie wspomniał konkretnie o jQuery, jest całkowicie nieistotny: odpowiedź @ RobertKoritnik była dla mnie idealna.
Dave Land

1
Nawiasem mówiąc, usługa Bing wyświetla przykładowy kod w wynikach wyszukiwania wyrażenia „zapobiegaj przewijaniu elementu przodka za pomocą scrollintoview”. :-)
Dave Land

2

Korzystając z pomysłu Brillego, oto rozwiązanie, które przewija się (pionowo) tylko wtedy, gdy element NIE jest obecnie widoczny. Chodzi o to, aby uzyskać obwiednię rzutni i element do wyświetlenia w przestrzeni współrzędnych okna przeglądarki. Sprawdź, czy jest widoczny, a jeśli nie, przewiń o wymaganą odległość, aby element był wyświetlany u góry lub u dołu rzutni.

    function ensure_visible(element_id)
    {
        // adjust these two to match your HTML hierarchy
        var element_to_show  = document.getElementById(element_id);
        var scrolling_parent = element_to_show.parentElement;

        var top = parseInt(scrolling_parent.getBoundingClientRect().top);
        var bot = parseInt(scrolling_parent.getBoundingClientRect().bottom);

        var now_top = parseInt(element_to_show.getBoundingClientRect().top);
        var now_bot = parseInt(element_to_show.getBoundingClientRect().bottom);

        // console.log("Element: "+now_top+";"+(now_bot)+" Viewport:"+top+";"+(bot) );

        var scroll_by = 0;
        if(now_top < top)
            scroll_by = -(top - now_top);
        else if(now_bot > bot)
            scroll_by = now_bot - bot;
        if(scroll_by != 0)
        {
            scrolling_parent.scrollTop += scroll_by; // tr.offsetTop;
        }
    }

2

Dodawanie więcej informacji do @Jescoposta.

  • Element.scrollIntoViewIfNeeded() non-standard WebKit methoddla przeglądarek Chrome, Opera, Safari.
    Jeśli element znajduje się już w widocznym obszarze okna przeglądarki, przewijanie nie następuje .
  • Element.scrollIntoView() metoda przewija element, na którym jest wywoływana, do widocznego obszaru okna przeglądarki.

Wypróbuj poniższy kod w mozilla.org scrollIntoView()linku. Opublikuj, aby zidentyfikować przeglądarkę

var xpath = '//*[@id="Notes"]';
ScrollToElement(xpath);

function ScrollToElement(xpath) {
    var ele = $x(xpath)[0];
    console.log( ele );

    var isChrome = !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime);
    if (isChrome) { // Chrome
        ele.scrollIntoViewIfNeeded();
    } else {
        var inlineCenter = { behavior: 'smooth', block: 'center', inline: 'start' };
        ele.scrollIntoView(inlineCenter);
    }
}

2

w moim kontekście zepchnąłby lepki pasek narzędzi z ekranu lub wszedł obok przycisku fab z wartością bezwzględną.

używając najbliższego rozwiązanego.

const element = this.element.nativeElement;
const table = element.querySelector('.table-container');
table.scrollIntoView({
  behavior: 'smooth', block: 'nearest'
});

1

miałem ten sam problem, naprawiłem go, usuwając transform:translateYCSS, który umieściłem na footerstronie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.