这是经典之作。您有父元素和子元素。子元素绝对定位,您希望用户滚动其内容。但是,当您到达子元素的底部时,父元素(也允许有滚动条)开始滚动。那是不可取的。我想重现的基本行为是“纽约时报”评论部分。对于example:
允许正文向下滚动,但当你在评论部分的底部时,向下滚动不会做任何事情。我认为在这种情况下的主要区别在于,当光标位于body元素上方时,我想让用户向下滚动。其他方法需要向正文添加一个类以防止正文中的任何滚动事件。我想我可以在Angular 2中使用一些Javascript来做到这一点,但这是我到目前为止失败的尝试:
我的子组件中有一个自定义指令:
<child-element scroller class="child"></child-element>
并且该指令应该停止将scroll事件传播到body元素:
import {Component} from 'angular2/core'
import {Directive, ElementRef, Renderer} from 'angular2/core';
@Directive({
selector: '[scroller]',
})
export class ScrollerDirective {
constructor(private elRef: ElementRef, private renderer: Renderer) {
renderer.listen(elRef.nativeElement, 'scroll', (event) => {
console.log('event!');
event.stopPropagation();
event.preventDefault();
})
}
}
它实际上会侦听事件但不会阻止传播。
Demo:向下滚动数字列表,当您到达底部时,其父元素开始向下滚动。那就是问题所在。
如果您有其他方法可以实现此目的,请告知我们。
由于
更新:根据GünterZöchbauer提供的答案,我试图在用户到达底部时阻止滚轮事件。这基本上是我目前在updated demo中所拥有的:
renderer.listen(elRef.nativeElement, 'wheel', (e) => {
console.log('event', e);
console.log('scrollTop', elRef.nativeElement.scrollTop);
console.log('lastScrollTop', lastScrollTop);
if (elRef.nativeElement.scrollTop == lastScrollTop && e.deltaY > 0) {
e = e || window.event;
if (e.preventDefault)
e.preventDefault();
e.returnValue = false;
}
else if (elRef.nativeElement.scrollTop == 0) {
lastScrollTop = -1;
}
else {
lastScrollTop = elRef.nativeElement.scrollTop;
}
}, false)
然而,逻辑是丑陋的,并不是很好。例如,当用户到达底部时,向上滚动一点并再次向下滚动,父组件稍微移动。有谁知道如何处理这个? (更好)实施?
更新2 :
This要好得多,但现在已经晚了,所以我明天再来看看。
答案 0 :(得分:6)
在我看来,我会建议一些更简单的方法:将任意类添加到任意父级,并阻止通过CSS overflow: hidden
滚动。
在这个例子中,我编写了指令,以防止父元素在元素存在时滚动,因为这是我想要的行为。您的用例应该绑定到mouseenter
和mouseleave
HTML:
<div add-class="noscroll" to="body">Some Content Here</div>
CSS:
.noscroll { overflow: hidden; }
TS:
import {Directive, AfterViewInit, OnDestroy, Input} from "@angular/core";
@Directive({
selector: '[add-class]'
})
export class AddClassDirective implements AfterViewInit, OnDestroy {
@Input('add-class')
className: string;
@Input('to')
selector: string;
ngOnDestroy(): void {
document.querySelector(this.selector).classList.remove(this.className);
}
ngAfterViewInit(): void {
document.querySelector(this.selector).classList.add(this.className);
}
}
答案 1 :(得分:4)
这是我迄今为止的最佳尝试。
renderer.listen(elRef.nativeElement, 'wheel', (e) => {
let el = elRef.nativeElement;
let conditions = ((el.scrollTop + el.offsetHeight > el.scrollHeight)) && e.deltaY > 0 || el.scrollTop === 0 & e.deltaY < 0;
if (conditions) {
e = e || window.event;
if (e.preventDefault)
e.preventDefault();
e.returnValue = false;
}
}, false)
它适用于Firefox,Chrome稳定版和测试版,但出于某种原因,Chrome开发人员的行为略有不同。如果用户在底部附近向下滚动(或者等效地向上滚动靠近顶部),则父元素移动一点。不幸的是,我注意到纽约时报的评论部分也有相同的annoyance。如果您有任何建议,请与我们联系。
我报告了Chrome dev中出现的问题,this到目前为止一直是回复。
答案 2 :(得分:3)
您无法阻止或停止传播scroll
事件。您需要阻止导致scroll
事件的事件。
答案 3 :(得分:1)
我遇到了类似的问题。我想在我的模态组件打开时禁用滚动。
以下是我如何解决它:
import { Component, HostListener } from '@angular/core';
@Component({
selector : 'app-modal',
templateUrl: './modal.component.html',
styleUrls : ['./modal.component.scss'],
})
export class ModalComponent {
@HostListener('wheel', ['$event'])
handleWheelEvent(event) {
event.preventDefault();
}
...
希望你觉得它很有用。
答案 4 :(得分:1)
Robert'answer 确实很有帮助,但是它已经过时了,对我没有先用。我对其进行了改进,使其适用于我,因此我想与您分享:
<div class="scrollable-inner-div" scroller-directive>
// Code
</div>
用于html之类的
response.send(result)
答案 5 :(得分:0)
overflow: hidden
隐藏垂直滚动条,这是我不想要的。
AngularX解决方案:
HTML:
<div class="overlay" (wheel)="onWheel($event)">
</div>
TS:
onWheel($event)
{
$event.preventDefault();
$event.stopPropagation();
}