2016-04-07 42 views
5

Questo è un classico. Hai un elemento genitore e un elemento figlio. L'elemento figlio è posizionato in modo assoluto e si desidera che l'utente scorra il suo contenuto. Tuttavia, quando si raggiunge la parte inferiore dell'elemento figlio, l'elemento padre (a cui è consentito anche avere barre di scorrimento) inizia a scorrere. Questo è indesiderabile. Il comportamento di base che voglio riprodurre è quello della sezione commenti del New York Times. Per example:Previene lo scorrimento dell'elemento figlio da propagare in Angular 2

enter image description here

Il corpo è consentito di scorrere verso il basso, ma quando si è in fondo la sezione dei commenti, scorrendo verso il basso non fa nulla. Penso che la differenza principale in questo caso sia che voglio far scorrere l'utente verso il basso quando il cursore è posizionato sopra l'elemento del corpo. Altri approcci richiedono di aggiungere una classe al corpo per prevenire qualsiasi evento di scorrimento nel corpo. Ho pensato di essere in grado di fare questo con un po 'di Javascript nel Angolare 2, ma questo è il mio tentativo è fallito finora:

enter image description here

Ho una direttiva personalizzato nel mio componente figlio:

<child-element scroller class="child"></child-element>

e della presente direttiva dovrebbe fermare la propagazione della manifestazione di scorrimento per l'elemento del corpo:

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

} 

In realtà ascolta l'evento ma non interrompe la propagazione.

Demo: scorrere verso il basso nell'elenco dei numeri e quando si raggiunge il fondo, l'elemento padre inizia a scorrere verso il basso. Questo è il problema.

Se si dispone di un altro approccio per realizzare questo, per favore fatemelo sapere.

Grazie

UPDATE: Sulla base della risposta fornita da Günter Zöchbauer, sto cercando di impedire l'evento ruota quando l'utente raggiunge il fondo. Questo è fondamentalmente ciò che ho finora in questo 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) 

Tuttavia, la logica è brutto e non funziona grande. Ad esempio, quando l'utente raggiunge il fondo, scorre leggermente verso l'alto e scorre nuovamente verso il basso, il componente principale si sposta leggermente. Qualcuno sa come affrontare questo? Un'implementazione (molto) migliore?

UPDATE 2:

This è molto meglio, ma è tardi, quindi mi controllerà di nuovo domani.

risposta

2
+0

Grazie. Molto interessante.Sto solo cercando di capire come usare l'evento wheel per evitare lo scrolling. Suppongo di dover rilevare quando l'utente ha spostato verso il basso ma non vedo un valore sull'oggetto evento per farlo. –

+0

Vedere http://stackoverflow.com/questions/36468318/tracking-scroll-position-and-notifying-other-components-about-it-angular2/36468377?noredirect=1#comment60554485_36468377 e http://stackoverflow.com/ domande/36471927/eventemitter-non-lavoro-su-chrome-safari - in particolare l'ultimo commento sulla risposta. –

+0

Penso di avere qualcosa che funzioni, ma sto lottando con la logica corretta. Aggiornerò la mia domanda –

2

Questo è il mio miglior tentativo finora.

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

E le grandi opere in Firefox, Chrome stabile e beta, ma per qualche ragione, Chrome dev si comporta in modo un po 'diverso. Se l'utente scorre verso il basso in modo molto difficile vicino al fondo (o in modo equivalente, scorre verso l'alto vicino alla cima), l'elemento genitore si muove leggermente. Purtroppo, ho notato che la sezione commenti del New York Times ha lo stesso annoyance. Se hai suggerimenti, fammi sapere.

Ho segnalato che il problema si è verificato in Chrome dev e this è stata la risposta finora.

3

Vorrei suggerire qualcosa di più semplice a mio parere: aggiungere una classe arbitraria a un genitore arbitrario e impedire lo scorrimento tramite CSS overflow: hidden.

In questo esempio, ho scritto la direttiva per impedire al genitore di scorrere mentre l'elemento esiste del tutto, poiché questo era il mio comportamento desiderato. Invece di OnDestroy e AfterViewInit, per il vostro caso d'uso si dovrebbe legarsi a mouseenter e 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); 
    } 
} 
0

ho avuto il problema simile. Volevo disabilitare lo scorrimento mentre il mio componente modale è stato aperto.

Ecco come ho risolto:

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

... 

Spero vi sia utile.

+0

che ne dici di scroll scrolling? – godblessstrawberry