Angular 4 - 如何在div进入视口时触发动画?
我一直在建设一个使用Angular 4的新网站,我试图重新创建一个效果,当div变成可见的时候(当你向下滚动屏幕时),然后可以触发一个角度动画来滑动div在形式方面。Angular 4 - 如何在div进入视口时触发动画?
我已经能够在过去使用jQuery之外的Angular 4做到这一点,但我想尝试使用本地Angular 4动画创建相同的效果。
任何人都可以为我提供关于如何在div进入视图时触发动画的建议(即,当它进入视口时向下滚动到页面的下半部分?)。我已经写过幻灯片动画了,但是我不知道如何通过滚动来触发它,当一个div在稍后的日期变为可见的时候可以看到视口。
谢谢大家!
我创建了一个指令,只要元素完全处于视图内或者其上边缘已经到达视图的上边缘,就会发出一个事件。
这里有一个plunker:https://embed.plnkr.co/mlez1dXjR87FNBHXq1YM/
它这样使用:
<div (appear)="onAppear()">...</div>
这里的指令:
import {
ElementRef, Output, Directive, AfterViewInit, OnDestroy, EventEmitter
} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {Subscription} from 'rxjs/Subscription';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/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.element.nativeElement.offsetHeight;
this.windowHeight = window.innerHeight;
}
saveScrollPos() {
this.scrollPos = window.scrollY;
}
getOffsetTop(element: any){
let offsetTop = element.offsetTop || 0;
if(element.offsetParent){
offsetTop += this.getOffsetTop(element.offsetParent);
}
return offsetTop;
}
checkVisibility(){
if(this.isVisible()){
// double check dimensions (due to async loaded contents, e.g. images)
this.saveDimensions();
if(this.isVisible()){
this.unsubscribe();
this.appear.emit();
}
}
}
isVisible(){
return this.scrollPos >= this.elementPos || (this.scrollPos + this.windowHeight) >= (this.elementPos + this.elementHeight);
}
subscribe(){
this.subscriptionScroll = Observable.fromEvent(window, 'scroll').startWith(null)
.subscribe(() => {
this.saveScrollPos();
this.checkVisibility();
});
this.subscriptionResize = Observable.fromEvent(window, 'resize').startWith(null)
.subscribe(() => {
this.saveDimensions();
this.checkVisibility();
});
}
unsubscribe(){
if(this.subscriptionScroll){
this.subscriptionScroll.unsubscribe();
}
if(this.subscriptionResize){
this.subscriptionResize.unsubscribe();
}
}
ngAfterViewInit(){
this.subscribe();
}
ngOnDestroy(){
this.unsubscribe();
}
}
为ie11兼容性,你可以改变window.scrollY到document.documentElement.scrollTop。 –
这不适用于页面上的多个元素 – godblessstrawberry
我创建了一个基本组件,它提供了一个标志wasoOnce,如果组件完全位于视图内或其上边缘已到达视图的上边缘,则该组件将变为真。
@Injectable()
export class AppearOnce implements AfterViewInit, OnDestroy {
appearedOnce: boolean;
elementPos: number;
elementHeight: number;
scrollPos: number;
windowHeight: number;
subscriptionScroll: Subscription;
subscriptionResize: Subscription;
constructor(private element: ElementRef, private cdRef: ChangeDetectorRef){}
onResize() {
this.elementPos = this.getOffsetTop(this.element.nativeElement);
this.elementHeight = this.element.nativeElement.clientHeight;
this.checkVisibility();
}
onScroll() {
this.scrollPos = window.scrollY;
this.windowHeight = window.innerHeight;
this.checkVisibility();
}
getOffsetTop(element: any){
let offsetTop = element.offsetTop || 0;
if(element.offsetParent){
offsetTop += this.getOffsetTop(element.offsetParent);
}
return offsetTop;
}
checkVisibility(){
if(!this.appearedOnce){
if(this.scrollPos >= this.elementPos || (this.scrollPos + this.windowHeight) >= (this.elementPos + this.elementHeight)){
this.appearedOnce = true;
this.unsubscribe();
this.cdRef.detectChanges();
}
}
}
subscribe(){
this.subscriptionScroll = Observable.fromEvent(window, 'scroll').startWith(null)
.subscribe(() => this.onScroll());
this.subscriptionResize = Observable.fromEvent(window, 'resize').startWith(null)
.subscribe(() => this.onResize());
}
unsubscribe(){
if(this.subscriptionScroll){
this.subscriptionScroll.unsubscribe();
}
if(this.subscriptionResize){
this.subscriptionResize.unsubscribe();
}
}
ngAfterViewInit(){
this.subscribe();
}
ngOnDestroy(){
this.unsubscribe();
}
}
您可以简单地扩展这个组件,并通过继承
@Component({
template: `
<div>
<div *ngIf="appearedOnce">...</div>
...
</div>
`
})
class MyComponent extends AppearOnceComponent {
...
}
利用appearedOnce财产记住调用超()如果你需要重写构造函数或lifecyclehooks。
(编辑)plunker: https://embed.plnkr.co/yIpA1mI1b9kVoEXGy6Hh/
(编辑)我已经变成了下面另一个答案一个指令这一点。
不知道,但可以在这个环节是有帮助的https://angular.io /docs/ts/latest/guide/animations.html#!#parallel-animation-groups? – sandyJoshi
嗨桑迪,我确实看了看,并行动画组的方法有助于链动画,但它似乎没有办法触发当div进入视点后滚动到页面的低点可能发生在当使用决定向下滚动到div时的可变时间。你知道这个UI行为的任何解决方案吗? – Ultronn