Przewiń do elementu po kliknięciu w Angular 4

109

Chcę mieć możliwość przewijania do celu po naciśnięciu przycisku. Myślałem o czymś takim.

<button (click)="scroll(#target)">Button</button>

A w mojej component.tsmetodzie jak.

scroll(element) {
    window.scrollTo(element.yPosition)
}

Wiem, że powyższy kod nie jest prawidłowy, ale tylko po to, aby pokazać, o czym myślę. Właśnie zacząłem uczyć się Angular 4 bez wcześniejszego doświadczenia z Angular. Szukałem czegoś takiego, ale wszystkie przykłady znajdują się w AngularJs, który znacznie różni się od Angular 4

BuZZ-dEE
źródło
1
Twoja składnia nie stwarza problemów, ale musisz zdefiniować, czym jest #target.
wannadream
1
Więc to powinno działać? Kiedy używam dowolnego numeru i dzwonię do window.scrollTo (500) w mojej funkcji, nic się nie dzieje. Myślałem, że tym elementem będzie HTMLElement
Ale prawda, czym jest #target, Angular tego nie rozwiąże? Możesz najpierw przetestować scroll () bez parametru.
wannadream
Tak, próbowałem (click) = "scroll ()" w moim przycisku i window.scrollTo (0, 500) w komponencie, ale nic się nie dzieje
2
Ale kiedy robię window.scrollTo (0, 500) w konstruktorze z opóźnieniem 500

Odpowiedzi:

161

Możesz to zrobić tak:

<button (click)="scroll(target)"></button>
<div #target>Your target</div>

a następnie w swoim komponencie:

scroll(el: HTMLElement) {
    el.scrollIntoView();
}

Edycja: Widzę komentarze stwierdzające, że to już nie działa, ponieważ element jest niezdefiniowany. Stworzyłem przykład StackBlitz w Angular 7 i nadal działa. Czy ktoś może podać przykład, gdzie to nie działa?

Frank Modica
źródło
1
@ N15M0_jk Tak, jest też obiekt, który możesz przekazać z innymi opcjami, w zależności od potrzeb. developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
Frank Modica
1
@Anthony Pozwala odwołać się do elementu, który chcesz przekazać do scrollfunkcji w komponencie. Zwróć uwagę, że wywoływane jest zdarzenie kliknięcia scroll(target). Jeśli chcesz uzyskać dostęp do elementu z wnętrza komponentu bez konieczności przekazywania elementu, możesz użyć @ViewChild.
Frank Modica,
2
Teraz działa dobrze ze mną. Ale zanim popełniłem głupi błąd i użyłem go id="target"zamiast #targeti dało mi to „el is undefined error”!
yashthakkar1173
1
Uważam, że niezdefiniowany błąd występuje, gdy element z elementem #targetznajduje się wewnątrz an *ngIf, ale powinien działać, jeśli użyjesz @ViewChildmetody w linku z @abbastec
spectacularbob
1
proste i schludne. Działa dla mnie w Angular 10
griffinleow
53

Oto jak to zrobiłem, używając Angular 4.

Szablon

<div class="col-xs-12 col-md-3">
  <h2>Categories</h2>
  <div class="cat-list-body">
    <div class="cat-item" *ngFor="let cat of web.menu | async">
      <label (click)="scroll('cat-'+cat.category_id)">{{cat.category_name}}</label>
    </div>
  </div>
</div>

dodaj tę funkcję do komponentu.

scroll(id) {
  console.log(`scrolling to ${id}`);
  let el = document.getElementById(id);
  el.scrollIntoView();
}
LH7
źródło
1
Nie ustawiłeś elementu elementRefs ani identyfikatorów HTML w swoim szablonie. Gdzie dokładnie jest element „cat -” + cat.category_id, do którego przewijasz?
Keegan
1
To jest lepsza odpowiedź. Możesz umieścić zwój na innym elemencie.
Dale Nguyen,
1
To powinna być akceptowana odpowiedź. Praca dla Angular 9
16
49

W rzeczywistości istnieje sposób na osiągnięcie tego w czystym javascript bez użycia setTimeoutlub requestAnimationFramelub jQuery.

Krótko mówiąc, znajdź element w scrollView, do którego chcesz przewinąć, i użyj scrollIntoView.

el.scrollIntoView({behavior:"smooth"});

Oto plunkr .

Jon
źródło
3
Ta odpowiedź jest inna na dwa sposoby: 1. Jest to animowane płynne przewijanie, a nie skok. 2. Ta odpowiedź nie przewija okna, ale przesuwa przewijany widok w obrębie okna. Na przykład, jeśli masz poziomy przewijany widok w oknie. Sprawdź przykład w plunkr.
Jon,
1
scrollIntoView scrollIntoViewOptions (obiekt jako argument) jest obecnie zgodny tylko z przeglądarką Firefox.
Jesús Fuentes
Działa dobrze w Chrome i Firefox, ale nie w Safari.
Yamashiro Rion
36

W Angular 7 działa idealnie

HTML

<button (click)="scroll(target)">Click to scroll</button>
<div #target>Your target</div>

W komponencie

scroll(el: HTMLElement) {
    el.scrollIntoView({behavior: 'smooth'});
}
Robert S.
źródło
2
bonus za {zachowanie: 'gładkie'}
Squapl Recipes
To działa dla mnie… specjalne podziękowania za {zachowanie: 'smooth'}
Vibhu kumar
1
To nie zadziała, jeśli #targetzostanie zdefiniowane po przycisku, co ma znaczenie, jeśli masz pływający nagłówek, na przykład ...
Jonathan
22

Jon ma właściwą odpowiedź i to działa w moich projektach Angular 5 i 6.

Gdybym chciał kliknąć, aby płynnie przewijać od paska nawigacyjnego do stopki:

<button (click)="scrollTo('.footer')">ScrolltoFooter</button>
<footer class="footer">some code</footer>

scrollTo(className: string):void {
   const elementList = document.querySelectorAll('.' + className);
   const element = elementList[0] as HTMLElement;
   element.scrollIntoView({ behavior: 'smooth' });
}

Ponieważ chciałem przewinąć z powrotem do nagłówka ze stopki, utworzyłem usługę, w której znajduje się ta funkcja, i wstrzyknąłem ją do komponentów nawigacyjnych i stopki i przekazałem w razie potrzeby w nagłówku lub stopce. pamiętaj tylko, aby faktycznie nadać deklaracjom komponentów używane nazwy klas:

<app-footer class="footer"></app-footer>
Stephen E.
źródło
15

Inny sposób na zrobienie tego w Angular:

Narzut:

<textarea #inputMessage></textarea>

Dodaj ViewChild()nieruchomość:

@ViewChild('inputMessage')
inputMessageRef: ElementRef;

Przewiń w dowolne miejsce wewnątrz komponentu za pomocą scrollIntoView()funkcji:

this.inputMessageRef.nativeElement.scrollIntoView();
Schnapz
źródło
12

Możesz przewinąć do dowolnego elementu w swoim widoku, używając bloku kodu poniżej. Zauważ, że cel (id elementuref ) może znajdować się na dowolnym prawidłowym tagu HTML.

W widoku (plik html)

<div id="target"> </div>
<button (click)="scroll()">Button</button>
 

  

w .tsaktach,

scroll() {
   document.querySelector('#target').scrollIntoView({ behavior: 'smooth', block: 'center' });
}
Ifesinachi Bryan
źródło
7

Możesz to osiągnąć, używając odniesienia do kątowego elementu DOM w następujący sposób:

Oto przykład w stackblitz

szablon komponentu:

<div class="other-content">
      Other content
      <button (click)="element.scrollIntoView({ behavior: 'smooth', block: 'center' })">
        Click to scroll
      </button>
    </div>
    <div id="content" #element>
      Some text to scroll
</div>
Andres Gardiol
źródło
7

W Angular możesz użyć ViewChildi ElementRef: nadaj elementowi HTML ref

<div #myDiv > 

i wewnątrz twojego komponentu:

import { ViewChild, ElementRef } from '@angular/core';
@ViewChild('myDiv') myDivRef: ElementRef;

możesz użyć, this.myDivRef.nativeElementaby dostać się do swojego żywiołu

M.Amer
źródło
Jest to dobre rozwiązanie, ale problem polega na tym, że działa tylko po ponownym załadowaniu karty, ale nie przy użyciu routerLink. Jakieś rozwiązanie tego problemu?
Ahsan
-8

Zrobiłem coś takiego, o co prosisz, używając jQuery do znalezienia elementu (na przykład document.getElementById(...)) i używając .focus()wywołania.

Kenneth Salomon
źródło
3
Czy jQuery jest naprawdę potrzebne podczas korzystania z Angular?
Nie jestem w 100% pewien, ale byłem w środowisku, które nie zostało sprawdzone i refaktoryzowane dla Angular2, więc nie szukałem zbytnio rozwiązania w Angular i po prostu poszedłem z czymś, do czego wiedziałem, że będę miał dostęp.
Kenneth Salomon
8
Nie powinieneś używać Jquery i Angular
Stefdelec
2
Tak, tak, wiele się nauczyłem i wszyscy komentują, że nie powinienem używać jQuery. Nie mówisz niczego, czego inni nie skomentowali tuż nad tobą.
Kenneth Salomon
Głosowałem za pokorą. Chciałbym dodać, że odpowiedzi jQuery mają pewną wartość dla tych, którzy przechodzą na platformy SPA. Pokazując, jak to robiliśmy i czytając komentarze rekomendujące inne rozwiązania.
B2K,
-17

Możesz to zrobić za pomocą jquery:

kod TS:

    scrollTOElement = (element, offsetParam?, speedParam?) => {
    const toElement = $(element);
    const focusElement = $(element);
    const offset = offsetParam * 1 || 200;
    const speed = speedParam * 1 || 500;
    $('html, body').animate({
      scrollTop: toElement.offset().top + offset
    }, speed);
    if (focusElement) {
      $(focusElement).focus();
    }
  }

Kod HTML :

<button (click)="scrollTOElement('#elementTo',500,3000)">Scroll</button>

Zastosuj to do elementów, które chcesz przewijać:

<div id="elementTo">some content</div>

Oto próbka stackblitz.

Gns
źródło
1
Z wyjątkiem tego, że ta operacja wymaga, aby rozwiązania TypeScript nie obejść się z przestarzałym frameworkiem (głosowanie w dół)
popiół
to jest rozwiązanie na maszynie.
Gns
1
Przegapiłeś mój punkt widzenia, twoja odpowiedź używa jQuery (mogę dodać w najbardziej nieefektywny sposób), zamiast po prostu używać ES *. Twoje stałe również nie deklarują swojego typu. To tylko zły przykład ze złą logiką używającą jQuery, o co nie pytano.
popiół