webentwicklung-frage-antwort-db.com.de

Winkel 4 - Scroll-Animation

Ich erstelle eine Webseite mit vollen Seitenbreitenhöhen div .. .. Beim Scrollen habe ich zwei Arten von Methoden.

/ - auf Klick scrollen

//HTML
<a (click)="goToDiv('about')"></a>

//JS
    goToDiv(id) {
        let element = document.querySelector("#"+id);
        element.scrollIntoView(element);
      }

auf HostListener blättern

  @HostListener("window:scroll", ['$event'])
  onWindowScroll($event: any): void {
    this.topOffSet = window.pageYOffset;
    //window.scrollTo(0, this.topOffSet+662);
  }

1. Wie füge ich einen Scroll-Animationseffekt hinzu?

So wie :

$('.scroll').on('click', function(e) {
    $('html, body').animate({
        scrollTop: $(window).height()
    }, 1200);
});

2. Und wie verwende ich HostListener, um zum nächsten Div zu scrollen?

22
Sumit Ridhal

Das macht Spaß. Die Lösung, wie bei den meisten Dingen 2, ist beobachtbar.

  getTargetElementRef(currentYPos: int): ElementRef {
      // you need to figure out how this works
      // I can't comment much on it without knowing more about the page
      // but you inject the Host ElementRef in the component / directive constructor and use normal vanillaJS functions to find other elements
  }
  //capture the scroll event and pass to a function that triggers your own event for clarity and so you can manually trigger
  scrollToSource: Subject<int> = new Subject<int>();
  @HostListener("window:scroll", ['$event'])
  onWindowScroll($event: any): void {
    var target = getTargetElementRef(window.pageYOffset);
    this.scrollTo(target);
  }

  scrollTo(target: ElementRef): void {
     // this assumes you're passing in an ElementRef, it may or may not be appropriate, you can pass them to functions in templates with template variable syntax such as: <div #targetDiv>Scroll Target</div> <button (click)="scrollTo(targetDiv)">Click To Scroll</button>
     this.scrollToSource.next(target.nativeElement.offsetTop);
  }

  //switch map takes the last value emitted by an observable sequence, in this case, the user's latest scroll position, and transforms it into a new observable stream
  this.scrollToSource.switchMap(targetYPos => {
       return Observable.interval(100) //interval just creates an observable stream corresponding to time, this emits every 1/10th of a second. This can be fixed or make it dynamic depending on the distance to scroll
           .scan((acc, curr) =>  acc + 5, window.pageYOffset) // scan takes all values from an emitted observable stream and accumulates them, here you're taking the current position, adding a scroll step (fixed at 5, though this could also be dynamic), and then so on, its like a for loop with +=, but you emit every value to the next operator which scrolls, the second argument is the start position
           .do(position => window.scrollTo(0, position)) /// here is where you scroll with the results from scan
           .takeWhile(val => val < targetYPos); // stop when you get to the target
  }).subscribe(); //don't forget!

Mit einem Klick ist das einfach zu bedienen. Sie binden einfach scrollTo an einen Klick

Dies funktioniert nur beim Scrollen in eine Richtung. Dies sollte jedoch den Einstieg erleichtern. Sie können den Scan intelligenter machen, so dass er subtrahiert wird, wenn Sie nach oben gehen müssen, und stattdessen eine Funktion in take verwenden.

10
bryan60

Sie können auch die Eigenschaft css verwenden scroll-behaviour: smooth

in Kombination mit var yPosition = 1000; window.scrollTo(0,yPosition)

Ref: https://developer.mozilla.org/fr/docs/Web/CSS/scroll-behavior

3
Julien

Die Antwort von @bryan60 funktioniert, aber ich fühlte mich nicht wohl damit, und ich zog es vor, TimerObservable zu verwenden, was für andere Teamkollegen weniger verwirrend erscheint und auch für zukünftige Anwendungen leichter anzupassen ist.

Ich schlage vor, Sie haben einen gemeinsamen Dienst, wenn Sie DOM berühren oder mit Bildlauf- und anderen Problemen im Zusammenhang mit HTML-Elementen arbeiten. Dann können Sie diese Methode für diesen Dienst verwenden (andernfalls macht es für die Komponente keine Probleme).

  // Choose the target element (see the HTML code bellow):
  @ViewChild('myElement') myElement: ElementRef;

  this.scrollAnimateAvailable:boolean;

animateScrollTo(target: ElementRef) {
    if (this.helperService.isBrowser()) {
      this.scrollAnimateAvailable = true;
      TimerObservable
        .create(0, 20).pipe(
        takeWhile(() => this.scrollAnimateAvailable)).subscribe((e) => {
        if (window.pageYOffset >= target.nativeElement.offsetTop) {
          window.scrollTo(0, window.pageYOffset - e);
        } else if (window.pageYOffset <= target.nativeElement.offsetTop) {
          window.scrollTo(0, window.pageYOffset + e);
        }

        if (window.pageYOffset + 30 > target.nativeElement.offsetTop && window.pageYOffset - 30 < target.nativeElement.offsetTop) {
          this.scrollAnimateAvailable = false;
        }

      });
    }

  }



 scrollToMyElement(){
   this.animateScrollTo(this.myElement)
  }

Sie müssen das Element an diese Methode übergeben. So können Sie es machen:

<a (click)="scrollToMyElement()"></a>
<!-- Lots of things here... -->
<div #myElement></div>
0
M98