Lo scorrimento del div figlio fa scorrere la finestra, come lo interrompo?


Risposte:


68

Puoi disattivare lo scorrimento dell'intera pagina facendo qualcosa del genere:

<div onmouseover="document.body.style.overflow='hidden';" onmouseout="document.body.style.overflow='auto';"></div>

33
Bene, ma fa scomparire la barra di scorrimento del browser ogni volta che passi il mouse sopra il div.
cstack

@cstack hai ragione, ecco perché la risposta di OP (Jeevan) è migliore.
Imran Bughio

2
Molte rotelle di scorrimento del browser scompaiono e riappaiono in base all'utente che sposta il mouse ora, quindi il commento sopra non è più un problema.
Keith Holliday

Tuttavia, questa soluzione non funziona quando la pagina è incorporata in un iframe.
Gautam Krishnan

5
non una soluzione. impostando l'overflow su nascosto si nasconde la barra di scorrimento che improvvisamente riformatta tutto il contenuto dell'elemento esterno. inoltre, questo presuppone che l'elemento esterno sia body ma potrebbe essere un altro div a scorrimento.
robisrob

43

Trovato la soluzione.

http://jsbin.com/itajok

Questo è ciò di cui avevo bisogno.

E questo è il codice.

http://jsbin.com/itajok/edit#javascript,html

Utilizza un plug-in jQuery.


Aggiornamento a causa di avviso di deprecazione

Da jquery-mousewheel :

Il vecchio comportamento di aggiungere tre argomenti ( delta, deltaXe deltaY) al gestore di eventi è ora deprecato e verrà rimosso nelle versioni successive.

Quindi, event.deltaYora deve essere utilizzato:

var toolbox = $('#toolbox'),
    height = toolbox.height(),
    scrollHeight = toolbox.get(0).scrollHeight;

toolbox.off("mousewheel").on("mousewheel", function (event) {
  var blockScrolling = this.scrollTop === scrollHeight - height && event.deltaY < 0 || this.scrollTop === 0 && event.deltaY > 0;
  return !blockScrolling;
});

Demo


6
Il tuo link utilizza github per js e interruzioni perché il tipo di contenuto blah blah qui funziona: jsbin.com/itajok/207
Michael J. Calkins

Entrambi i jsbins non sembrano funzionare nell'emulatore del dispositivo Chrome e sull'iPhone. Qualcuno sa se funziona ancora?
Dirk Boer

2
La tua "soluzione" funziona solo per gli eventi di scorrimento del mouse, non per pagina su / giù o per i tasti freccia.
Scott

Perché qui è richiesto "off"?
Brad Johnson

16

La soluzione scelta è un'opera d'arte. Ho pensato che fosse degno di un plugin ...

$.fn.scrollGuard = function() {
    return this
        .on( 'wheel', function ( e ) {
            var event = e.originalEvent;
            var d = event.wheelDelta || -event.detail;
            this.scrollTop += ( d < 0 ? 1 : -1 ) * 30;
            e.preventDefault();
        });
};    

Questo è stato un inconveniente continuo per me e questa soluzione è così pulita rispetto ad altri hack che ho visto. Curioso di sapere di più su come funziona e su quanto sarebbe ampiamente supportato, ma saluta Jeevan e chiunque abbia originariamente inventato questo. BTW - l'editor di risposte di stackoverflow ha bisogno di questo!

AGGIORNARE

Credo che questo sia meglio in quanto non cerca di manipolare affatto il DOM, previene solo il bubbling condizionatamente ...

$.fn.scrollGuard2 = function() {
  return this
    .on( 'wheel', function ( e ) {
      var $this = $(this);
      if (e.originalEvent.deltaY < 0) {
        /* scrolling up */
        return ($this.scrollTop() > 0);
      } else {
        /* scrolling down */
        return ($this.scrollTop() + $this.innerHeight() < $this[0].scrollHeight);
      }
    })
  ;
};    

Funziona alla grande in Chrome e molto più semplice di altre soluzioni ... fammi sapere come se la cava altrove ...

VIOLINO


3
l'aggiunta dell'evento DOMMouseScroll lo fa funzionare con Firefox → jsfiddle.net/chodorowicz/egqy7mbz/1
chodorowicz

Sono sorpreso che questo non sia scritto in jquery. Ho pensato che uno dei punti principali fosse non doversi preoccupare del browser che stai utilizzando.
robisrob

in realtà sembra che entrambi siano deprecati ... wheelevento
robisrob

Ciò si traduce in uno scorrimento notevolmente più a scatti in Chrome sul mio Macbook. La soluzione accettata non presenta questo problema.
Danvk

deludente. ci sono così tante versioni differenti di questo. sembra un aspetto importante dell'interfaccia utente, ed è davvero sorprendente che questo sia il comportamento predefinito quando è così poco intuitivo. Ovviamente il browser è in grado di sapere che il div di scorrimento interno è al suo limite per poter invece applicare l'evento alla finestra, quindi perché non ci sono handle disponibili per interrogarlo?
robisrob

8

Potresti usare un evento mouseover sul div per disabilitare la barra di scorrimento del corpo e quindi un evento mouseout per attivarlo di nuovo?

Ad esempio, l'HTML

<div onmouseover="disableBodyScroll();" onmouseout="enableBodyScroll();">
    content
</div>

E poi il javascript in questo modo:

var body = document.getElementsByTagName('body')[0];
function disableBodyScroll() {
    body.style.overflowY = 'hidden';
}
function enableBodyScroll() {
    body.style.overflowY = 'auto';
}

12
Puoi usarlo anche tu document.body.
Ry-

8

Ecco un modo cross-browser per farlo sull'asse Y, funziona su desktop e dispositivi mobili. Testato su OSX e iOS.

var scrollArea = this.querySelector(".scroll-area");
scrollArea.addEventListener("wheel", function() {
    var scrollTop = this.scrollTop;
    var maxScroll = this.scrollHeight - this.offsetHeight;
    var deltaY = event.deltaY;
    if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
        event.preventDefault();
    }
}, {passive:false});

scrollArea.addEventListener("touchstart", function(event) {
    this.previousClientY = event.touches[0].clientY;
}, {passive:false});

scrollArea.addEventListener("touchmove", function(event) {
    var scrollTop = this.scrollTop;
    var maxScroll = this.scrollHeight - this.offsetHeight;
    var currentClientY = event.touches[0].clientY;
    var deltaY = this.previousClientY - currentClientY;
    if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
        event.preventDefault();
    }
    this.previousClientY = currentClientY;
}, {passive:false});

Funziona alla grande! Wow, esattamente quello che ho cercato. Ha bisogno di decisamente più voti positivi.
delato468

Questa soluzione funziona abbastanza bene ma necessita di un piccolo aggiustamento: è necessario modificare il scrollTop === maxScroll by scrollTop >= maxScroll. Sembra essere strano su 1 caso, era necessario
tchiot.ludo

7

Ho scritto risolvendo questo problema

  var div;
  div = document.getElementsByClassName('selector')[0];

  div.addEventListener('mousewheel', function(e) {
    if (div.clientHeight + div.scrollTop + e.deltaY >= div.scrollHeight) {
      e.preventDefault();
      div.scrollTop = div.scrollHeight;
    } else if (div.scrollTop + e.deltaY <= 0) {
      e.preventDefault();
      div.scrollTop = 0;
    }
  }, false);

Una delle poche soluzioni qui che funziona senza che gli elementi della pagina saltino fastidiosamente a causa dell'impostazione dell'overflow nascosto.
Scettico

+1 questa è una soluzione solida. se lo colleghi a un contenitore scorrevole, vorrai che div in questo esempio sia e.currentTarget.
Matt

soluzione molto pulita. Grazie
Thinh Bui

Funzionava con Chrome 61.0.3163.100 e Safari 11.0, ma non in FireFox 56.0 (Mac OS El Capitan)
BigJ

Questa è la migliore soluzione nativa. Tuttavia, falsenon è necessario specificarlo addEventListenerpoiché è l'impostazione predefinita. Inoltre, i confronti dovrebbero essere semplici disuguaglianze ( >e <), non >=o <=.
Domande Quolonel

6

Se capisco correttamente la tua domanda, allora vuoi impedire lo scorrimento del contenuto principale quando il mouse è sopra un div (diciamo una barra laterale). Per questo, la barra laterale potrebbe non essere figlia del contenitore a scorrimento del contenuto principale (che era la finestra del browser), per evitare che l'evento di scorrimento si propaghi al suo genitore.

Ciò potrebbe richiedere alcune modifiche al markup nel modo seguente:

<div id="wrapper"> 
    <div id="content"> 
    </div> 
</div> 
<div id="sidebar"> 
</div> 

Guarda che funziona in questo violino di esempio e confrontalo con questo violino di esempio che ha un comportamento di uscita del mouse leggermente diverso dalla barra laterale.

Vedi anche scorrere solo un particolare div con la barra di scorrimento principale del browser .


In questo caso la barra laterale è fuori dal div wrapper. Quindi non penso che la pergamena rimbalzerà al genitore
Jeevan

Con "questo caso" intendi il tuo caso? In caso contrario: hai esattamente ragione. In tal caso: se la tua pagina scorre alla fine dello scorrimento del div, il messaggio di scorrimento bolle al div genitore, quindi penso che la tua pagina e div non siano fratelli, ma genitore e figlio.
NGLN

Sì, Page è il genitore del mio div, quindi quando raggiungi la fine, inizia a scorrere la pagina, cosa che non voglio.
Jeevan

Se non puoi rendere il tuo div un fratello del contenuto principale, questo problema non può essere risolto solo con HTML + CSS. È il comportamento predefinito.
NGLN

1
Penso che questa sia la soluzione più efficiente di tutte le risposte fornite; con un buon markup pulito alla base di una pagina, sono necessari molti meno hack CSS e JS per ottenere il comportamento desiderato.

6

Come risposto qui , la maggior parte dei browser moderni ora supporta la overscroll-behavior: none;proprietà CSS, che impedisce lo scorrimento concatenato. Ed è tutto, solo una riga!


2
Questa dovrebbe essere la risposta corretta nel 2020. Per il mio caso d'uso la soluzione migliore era overscroll-behavior: contain;.
Molo

3

questo disabilita lo scorrimento sulla finestra se si entra nell'elemento selettore. funziona come un fascino.

elements = $(".selector");

elements.on('mouseenter', function() {
    window.currentScrollTop = $(window).scrollTop();
    window.currentScrollLeft = $(window).scrollTop();
    $(window).on("scroll.prevent", function() {
        $(window).scrollTop(window.currentScrollTop);
        $(window).scrollLeft(window.currentScrollLeft);
    });
});

elements.on('mouseleave', function() {
    $(window).off("scroll.prevent");
});

Questa è davvero una soluzione funzionante. Ne avevo bisogno in puro js, ​​quindi l'ho riscritto. Se qualcuno ne ha bisogno, è qui . Per chiunque stia ancora cercando la soluzione, dovresti controllare la mia risposta di seguito .
Andriy Stolyar

2

Puoi disattivare lo scorrimento dell'intera pagina facendo qualcosa di simile ma visualizza la barra di scorrimento!

<div onmouseover="document.body.style.overflow='hidden'; document.body.style.position='fixed';" onmouseout="document.body.style.overflow='auto'; document.body.style.position='relative';"></div>

2
$this.find('.scrollingDiv').on('mousewheel DOMMouseScroll', function (e) {
  var delta = -e.originalEvent.wheelDelta || e.originalEvent.detail;
  var scrollTop = this.scrollTop;
  if((delta < 0 && scrollTop === 0) || (delta > 0 && this.scrollHeight - this.clientHeight - scrollTop === 0)) {
    e.preventDefault();
  }
});

1

Sulla base della risposta di ceed, ecco una versione che consente di annidare elementi protetti da scorrimento. Solo l'elemento su cui si trova il mouse scorrerà e scorre abbastanza facilmente. Anche questa versione è rientrata. Può essere utilizzato più volte sullo stesso elemento e rimuoverà e reinstallerà correttamente i gestori.

jQuery.fn.scrollGuard = function() {
    this
        .addClass('scroll-guarding')
        .off('.scrollGuard').on('mouseenter.scrollGuard', function() {
            var $g = $(this).parent().closest('.scroll-guarding');
            $g = $g.length ? $g : $(window);
            $g[0].myCst = $g.scrollTop();
            $g[0].myCsl = $g.scrollLeft();
            $g.off("scroll.prevent").on("scroll.prevent", function() {
                $g.scrollTop($g[0].myCst);
                $g.scrollLeft($g[0].myCsl);
            });
        })
        .on('mouseleave.scrollGuard', function() {
            var $g = $(this).parent().closest('.scroll-guarding');
            $g = $g.length ? $g : $(window);
            $g.off("scroll.prevent");
        });
};

Un modo semplice per utilizzarlo è aggiungere una classe, ad esempio scroll-guard, a tutti gli elementi della pagina su cui consenti lo scorrimento. Quindi usa $('.scroll-guard').scrollGuard()per proteggerli.


0

Se applichi uno overflow: hiddenstile, dovrebbe scomparire

modifica: in realtà ho letto la tua domanda male, questo nasconderà solo la barra di scorrimento ma non credo che sia quello che stai cercando.


1
Ho bisogno di entrambe le barre di scorrimento. Sto parlando del comportamento. Quando scorro con la trackball del mouse quando raggiungo la fine dello scorrimento del div, non deve scorrere l'intera pagina.
Jeevan

0

Non sono riuscito a ottenere nessuna delle risposte per funzionare in Chrome e Firefox, quindi ho pensato a questa fusione:

$someElement.on('mousewheel DOMMouseScroll', scrollProtection);

function scrollProtection(event) {
    var $this = $(this);
    event = event.originalEvent;
    var direction = (event.wheelDelta * -1) || (event.detail);
    if (direction < 0) {
        if ($this.scrollTop() <= 0) {
            return false;
        }
    } else {
        if ($this.scrollTop() + $this.innerHeight() >= $this[0].scrollHeight) {
            return false;
        }
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.