How To Use Angular 4 Animations To Scrolltop 0
Source:
I'm creating a webpage having full page width/height div's. While scrolling down I've two types of methods.
Scroll on Click
//HTML <a (click)="goToDiv('about')"></a> //JS goToDiv(id) { let element = certificate.querySelector("#"+id); element.scrollIntoView(element); }
Roll on HostListener
@HostListener("window:curlicue", ['$event']) onWindowScroll($event: any): void { this.topOffSet = window.pageYOffset; //window.scrollTo(0, this.topOffSet+662); }
1. How to add together a scrolling animation furnishings?
Only like :
$('.scroll').on('click', function(e) { $('html, torso').animate({ scrollTop: $(window).height() }, 1200); });
2. And how to use HostListener to scroll to next div?
This one is fun. The solution, equally with near things angular 2, is observables.
getTargetElementRef(currentYPos: int): ElementRef { // you need to figure out how this works // I can't annotate much on it without knowing more than nearly the page // but you lot inject the host ElementRef in the component / directive constructor and apply normal vanillaJS functions to find other elements } //capture the scroll event and pass to a part that triggers your own event for clarity and and then y'all tin manually trigger scrollToSource: Field of study<int> = new Subject<int>(); @HostListener("window:scroll", ['$outcome']) onWindowScroll($issue: any): void { var target = getTargetElementRef(window.pageYOffset); this.scrollTo(target); } scrollTo(target: ElementRef): void { // this assumes you lot're passing in an ElementRef, it may or may not be advisable, 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 concluding value emitted past an observable sequence, in this case, the user'southward latest scroll position, and transforms it into a new appreciable stream this.scrollToSource.switchMap( targetYPos => { return Observable.interval(100) //interval just creates an observable stream corresponding to time, this emits every ane/10th of a second. This tin be fixed or brand 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 +=, just you emit every value to the side by side operator which scrolls, the second argument is the kickoff position .exercise( position => window.scrollTo(0, position)) /// here is where you curlicue with the results from scan .takeWhile( val => val < targetYPos); // terminate when yous get to the target }).subscribe(); //don't forget!
With a click this is easy to use. You simply bind scrollTo to a click
This only works for scrolling in 1 management, Nevertheless this should get yous started. You can make browse smarter so it subtracts if you need to become upwards, and instead use a function inside takeWhile that figures out the correct termination condition based on if going up or down.
edit: rxjs five+ compatible version
this.scrollToSource.piping(switchMap( targetYPos => interval(100).pipage( //interval just creates an observable stream respective to time, this emits every ane/10th of a second. This can be fixed or make it dynamic depending on the distance to ringlet scan((acc, curr) => acc + v, window.pageYOffset), // scan takes all values from an emitted observable stream and accumulates them, hither you're taking the electric current position, adding a coil stride (fixed at 5, though this could too be dynamic), and then so on, its like a for loop with +=, but y'all emit every value to the next operator which scrolls, the 2nd statement is the start position takeWhile( val => val < targetYPos)) // stop when you lot get to the target )).subscribe( position => window.scrollTo(0, position)); // hither is where y'all scroll with the results from browse
I spent days trying to effigy this out. Beingness a newbie I tried many things and none of them piece of work. Finally, I have a solution so I will post it here.
There are two steps:
- Animate when things announced.
- Make things appear when scrolling.
Part i: I found out these two keen tutorials for newbies:
- The almost basic one
- The ane that actually animates when stuff appears
Part 2: I simply discover the solution in this answer
Role 1 Stride by Footstep:
- Add together the line
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
to/src/app/app.module.ts
and then also:
@NgModule({ // Other arrays removed imports: [ // Other imports BrowserAnimationsModule ], })
- In the component.ts you want to animate, add together:
import { trigger,state,manner,transition,breathing } from '@angular/animations';
And and so:
@Component({ // Here goes the selector and templates and etc. animations: [ trigger('fadeInOut', [ country('void', style({ opacity: 0 })), transition('void <=> *', breathing(1000)), ]), ] })
- Finally, in the HTML item you desire to breathing, add together
[@fadeInOut]
.
If everything was done correctly, yous should at present have an animation (simply it happens as soon as the webpage loads and not when you scroll.
Part 2 Step by Step:
- Create a file .ts like for example
appear.ts
and copy-paste this code:
import { ElementRef, Output, Directive, AfterViewInit, OnDestroy, EventEmitter } from '@angular/core'; import { Observable, Subscription, fromEvent } from 'rxjs'; import { startWith } from 'rxjs/operators'; //import 'rxjs/add/observable/fromEvent'; //import 'rxjs/add together/operator/startWith'; @Directive({ selector: '[appear]' }) export class AppearDirective implements AfterViewInit, OnDestroy { @Output() appear: EventEmitter<void>; elementPos: number; elementHeight: number; scrollPos: number; windowHeight: number; subscriptionScroll: Subscription; subscriptionResize: Subscription; constructor(private element: ElementRef){ this.appear = new EventEmitter<void>(); } saveDimensions() { this.elementPos = this.getOffsetTop(this.element.nativeElement); this.elementHeight = this.chemical element.nativeElement.offsetHeight; this.windowHeight = window.innerHeight; } saveScrollPos() { this.scrollPos = window.scrollY; } getOffsetTop(chemical element: whatever){ let offsetTop = element.offsetTop || 0; if(chemical element.offsetParent){ offsetTop += this.getOffsetTop(chemical element.offsetParent); } return offsetTop; } checkVisibility(){ if(this.isVisible()){ // double check dimensions (due to async loaded contents, due east.g. images) this.saveDimensions(); if(this.isVisible()){ this.unsubscribe(); this.announced.emit(); } } } isVisible(){ return this.scrollPos >= this.elementPos || (this.scrollPos + this.windowHeight) >= (this.elementPos + this.elementHeight); } subscribe(){ this.subscriptionScroll = fromEvent(window, 'whorl').pipage(startWith(null)) .subscribe(() => { this.saveScrollPos(); this.checkVisibility(); }); this.subscriptionResize = fromEvent(window, 'resize').pipe(startWith(nix)) .subscribe(() => { this.saveDimensions(); this.checkVisibility(); }); } unsubscribe(){ if(this.subscriptionScroll){ this.subscriptionScroll.unsubscribe(); } if(this.subscriptionResize){ this.subscriptionResize.unsubscribe(); } } ngAfterViewInit(){ this.subscribe(); } ngOnDestroy(){ this.unsubscribe(); } }
- Import it using
import {AppearDirective} from './timeline/announced';
and add it to the imports every bit:
@NgModule({ declarations: [ // Other declarations AppearDirective ], // Imports and stuff
- Somewhere in the form do:
hasAppeared : boolean = fake; onAppear(){ this.hasAppeared = truthful; console.log("I have appeared!"); // This is a good idea for debugging }
- Finally, in the HTML add the ii post-obit:
(appear)="onAppear()" *ngIf="hasAppeared"
Y'all can bank check this is working by checking the console for the bulletin "I accept appeared!".
The @bryan60 answer works, only I was not comfortable with information technology, and I preferred to use TimerObservable
which seems less disruptive for other teammates and likewise easier to customize for time to come uses.
I suggest you lot have a shared service for times you're touching DOM, or working with scroll and other HTML element related issues; And then you can have this method on that service (otherwise having it on a component does not brand any problem)
// Cull the target element (see the HTML lawmaking 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 - due east); } else if (window.pageYOffset <= target.nativeElement.offsetTop) { window.scrollTo(0, window.pageYOffset + due east); } if (window.pageYOffset + 30 > target.nativeElement.offsetTop && window.pageYOffset - xxx < target.nativeElement.offsetTop) { this.scrollAnimateAvailable = faux; } }); } } scrollToMyElement(){ this.animateScrollTo(this.myElement) }
You need to pass the element to this method, here is how you tin practise it:
<a (click)="scrollToMyElement()"></a> <!-- Lots of things here... --> <div #myElement> </div>
Copyright © 2022 QueryThreads
All content on Query Threads is licensed under the Creative Commons Attribution-ShareAlike 3.0 license (CC BY-SA 3.0).
Source: https://www.querythreads.com/angular-4-scroll-animation/
Posted by: thomasexprooking.blogspot.com
0 Response to "How To Use Angular 4 Animations To Scrolltop 0"
Post a Comment