这个很有趣。与大多数 angular 2 一样,解决方案是 observables。
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!
只需单击一下,即可轻松使用。您只需将 scrollTo 绑定到单击
这仅适用于向一个方向滚动,但是这应该可以帮助您入门。您可以使扫描更智能,以便在需要向上时减去,而是在 takeWhile 中使用一个函数,该函数根据向上或向下计算正确的终止条件。
编辑:rxjs 5+ 兼容版本
this.scrollToSource.pipe(switchMap(targetYPos =>
interval(100).pipe( //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
takeWhile(val => val < targetYPos)) // stop when you get to the target
)).subscribe(position => window.scrollTo(0, position)); // here is where you scroll with the results from scan