注意:类似的问题是here,但似乎没有明显的答案可以应用。
问题:我有一个“转到顶部”按钮,其功能是将用户滚动到页面顶部。当用户实际上位于顶部时,它应该不可见。
目前,它的可见性是通过不透明度动画属性处理的,但是由于显示的原因,它可以与之交互:未应用任何不可见的属性。因此,我必须找到一种显示的方式:不透明度为0时不适用。
在Angular中,第一个实现是执行以下操作:
@HostListener('window:scroll', ['$event'])
scrolled(_event: Event) {
if (window.pageYOffset === 0) {
setTimeout(() => (this.noClick = true), 1000);
} else {
this.noClick = false;
}
this.show = window.pageYOffset > 0;
}
其中noClick
和show
是布尔值,并且noClick
应用于设置display:none的类,而show
应用于动画不透明度。
但是有一种竞争条件,用户可以在滚动到0后向下滚动,并且延迟仍然可以将noClick
设置为true。
我想考虑使用Observable解决此问题。
如果我有两个主题:
displayNone = new Subject<boolean>(); // only contains true values
displaySome = new Subject<boolean>(); // only contains false values
和一些事件代码:
@HostListener('window:scroll', ['$event'])
scrolled(_event: Event) {
if (window.pageYOffset === 0) {
this.displayNone.next(true);
} else {
this.displaySome.next(false);
}
this.show = window.pageYOffset > 0;
}
我需要为displayNone
功能构建一个可观察对象,其中如果displayNone
被延迟1000ms(动画时间),并且在这段时间内displaySome
发出,它必须忽略displayNone
我目前能找到的最接近的东西是这样的:
race(this.displaySome, this.displayNone.pipe(delay(1000)))
但是我的理解是,只需要评估一次就可以决定要通过哪一个。我需要不断对其进行评估。
答案 0 :(得分:0)
您不需要两个Observable即可显示/隐藏带有动画的按钮。最好的解决方案与问题的答案不同。我想同时回答这两个问题。
const X = 1000;
const obs$ = source$.pipe(
// emit values on a new inner Observable when the otherObservable$ emits
window(otherObservable$),
// skip all values on this inner Observable until a given time has passed
// (but not for the first inner Observable created before otherObservable$ emits)
mergeMap((w, i) => i == 0 ? w : w.pipe(skipUntil(timer(X))))
);
hasScrolledDown$: Observable<boolean>;
ngOnInit() {
this.hasScrolledDown$ = fromEvent(window, 'scroll').pipe(
throttleTime(20),
map(() => window.pageYOffset > 50)
)
}
ngIf
来显示/隐藏按钮,具体取决于Observable中的值。<button *ngIf="hasScrolledDown$ | async">
enter
和leave
状态更改添加动画。<button *ngIf="hasScrolledDown$ | async" [@fadeAnimation]>
export const fadeOutAnimation = animation([
style({ opacity: 1 }),
animate('200ms', style({ opacity: 0 }))
])
export const fadeInAnimation = animation([
style({ opacity: 0 }),
animate('200ms', style({ opacity: 1 }))
])
@Component({
selector: 'button-overview-example',
templateUrl: 'button-overview-example.html',
styleUrls: ['button-overview-example.css'],
animations: [
trigger('fadeAnimation', [
transition(':enter', [useAnimation(fadeInAnimation)]),
transition(':leave', [useAnimation(fadeOutAnimation)])
])
],
})