2016-04-07 32 views
5

這是一個經典。你有一個父母和一個孩子的元素。子元素絕對定位,您希望用戶滾動瀏覽其內容。但是,當您到達子元素的底部時,父元素(也允許具有滾動條)開始滾動。這是不可取的。我想重現的基本行爲是紐約時報的評論部分。對於example防止在Angular 2中傳播子元素的滾動

enter image description here

身體允許向下滾動,但是當你在註釋部分的底部,向下滾動不會做任何事情。我認爲這種情況的主要區別在於我想讓用戶在光標位於body元素上時向下滾動。其他方法需要向主體添加一個類來防止正文中的任何滾動事件。我想我能在角2位JavaScript來做到這一點,但是這是我的失敗嘗試至今:

enter image description here

我在我的孩子部件有一個自定義指令<child-element scroller class="child"></child-element>

和此指令是應該停止滾動事件到主體元件的傳播:

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:向下滾動數字列表,當您到達底部時,其父元素開始向下滾動。那就是問題所在。

如果您有其他方法來完成此操作,請讓我知道。

感謝

UPDATE:基於由君特Zö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是好多了,但已經晚了,所以我會再次檢查的明天。

回答

2
+0

謝謝。很有意思。我只是想弄清楚如何使用輪子事件來防止滾動。我想我需要檢測用戶何時滾動到底部,但我沒有看到事件對象上的值來做到這一點。 –

+0

請參閱http://stackoverflow.com/questions/36468318/tracking-scroll-position-and-notifying-other-components-about-it-angular2/36468377?noredirect=1#comment60554485_36468377和http://stackoverflow.com/問題/ 36471927/eventemitter-does-not-work-on-chrome-safari - 尤其是對答案的最後評論。 –

+0

我想我有一些工作,但我正在努力正確的邏輯。我會更新我的問題。 –

2

這是迄今爲止我最好的嘗試。

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) 

Demo

在Firefox,Chrome的穩定和β的偉大工程,但由於某些原因,Chrome瀏覽器開發的行爲有點不同。如果用戶在底部附近真的很難滾動(或者相當於在頂部附近滾動),父元素會稍微移動一點。不幸的是,我注意到紐約時報的評論部分也有相同的annoyance。如果您有任何建議,請告訴我。

我報告了在Chrome開發中發生的問題,並且this一直是迄今爲止的迴應。

3

在我看來,我會提出更直接的建議:將任意類添加到任意父級,並防止通過CSS滾動overflow: hidden

在這個例子中,我寫了一個指令來防止父元素在元素存在時滾動,因爲這是我期望的行爲。相反的OnDestroy和AfterViewInit的,爲您的使用情況下,你應該綁定到mouseentermouseleave

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); 
    } 
} 
0

我類似的問題。我想在我的模式組件打開時禁用滾動。

這裏是我是如何解決它:

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(); 
    } 

... 

希望你覺得它有用。

+0

觸摸滾動如何? – godblessstrawberry