web-dev-qa-db-fra.com

empêcher le défilement des bulles d'élément à la fenêtre

J'ai une fenêtre de boîte modale (pop-up) qui contient un iframe,
et à l'intérieur de ce iframe il y a un div qui est scrollable.

Lorsque je fais défiler la DIV interne de l'iframe et qu'elle a atteint sa limite supérieure ou inférieure,
la fenêtre du navigateur commence à défiler. c'est un comportement indésirable.

J'ai essayé quelque chose comme ça, qui tue le défilement de la fenêtre principale quand
onMouseEnter lorsque la souris entre dans la zone de la fenêtre contextuelle:

e.preventDefault () ne fonctionne pas comme il se doit pour une raison quelconque ...

$("#popup").mouseenter(function(){
   $(window).bind("scroll", function(e){
        e.preventDefault();
   }); 
}).mouseleave(function(){
    $(window).unbind("scroll");
});

Mettre à jour

On dirait que maintenant en 2013 e.preventDefault(); est suffisant ...

52
vsync

Résolu (pour les navigateurs modernes) à l'aide d'une simple propriété CSS:
Comportement excessif

body{
  height: 600px;
  overflow: auto;
}

section{
  width: 50%;
  height: 50%;
  overflow: auto;
  background: lightblue;
  overscroll-behavior: none; /*   <--- the trick    */
}

section::before{
  content: '';
  height: 200%;
  display: block;
}
<section>
 <input value='end' />
</section>

Appliquez simplement cette propriété de style à l'élément sur lequel le défilement doit être "verrouillé" et l'événement de défilement ne sera pas transmis à un élément parent pouvant également comporter un défilement.


Même démo que ci-dessus mais sans le truc:

body{
  height: 600px;
  overflow: auto;
}

section{
  width: 50%;
  height: 50%;
  overflow: auto;
  background: lightblue;
}

section::before{
  content: '';
  height: 200%;
  display: block;
}
<section>
 <input value='end' />
</section>

1
vsync

Désolé, autant que je sache, il est impossible d'annuler tout type d'événement de défilement.

Les deux W3 et MSDN say:

Cancelable  No
Bubbles     No

Je pense que vous devrez laisser cela aux auteurs du navigateur pour le réparer. Firefox (3.5 sous Linux, en tout cas) semble avoir un meilleur comportement pour moi: il ne fait défiler le parent que si l’enfant est déjà au bas/haut au moment où vous démarrez en utilisant la molette.

25
bobince

Si nous ne pouvons pas empêcher le défilement de la fenêtre, pourquoi ne pas l'annuler? C'est-à-dire capturer l'événement de défilement puis revenir à une position fixe.

Le code suivant verrouille l’axe des Y tant que l’on survole $("#popup"):

// here we store the window scroll position to lock; -1 means unlocked
var forceWindowScrollY = -1;

$(window).scroll(function(event) {
  if(forceWindowScrollY != -1 && window.scrollY != forceWindowScrollY) {
    $(window).scrollTop(forceWindowScrollY);    
  }
});

$("#popup").hover(function() {
  if(forceWindowScrollY == -1) {
    forceWindowScrollY = $(window).scrollTop();
  }
}, function() {
  forceWindowScrollY = -1;
});

J'utilise ceci pour la boîte de suggestion de requête sur http://bundestube.de/ (entrez quelques caractères dans la zone de recherche supérieure pour rendre le volet déroulant visible):

Screenshot

Cela fonctionne parfaitement dans Chrome/Safari (Webkit) et avec quelques problèmes de défilement dans Firefox et Opera. Pour une raison quelconque, cela ne fonctionne pas avec mon installation IE. Je suppose que cela a à voir avec la méthode de survol de jQuery, qui semble ne pas fonctionner correctement dans 100% des cas.

17

Je sais que c’est une question assez ancienne, mais comme c’est l’un des meilleurs résultats dans google ... j’ai dû annuler d’une manière ou d’une autre le scroll bullbling sans jQuery et ce code fonctionne pour moi:

function preventDefault(e) {
  e = e || window.event;
  if (e.preventDefault)
    e.preventDefault();
  e.returnValue = false;  
}

document.getElementById('a').onmousewheel = function(e) { 
  document.getElementById('a').scrollTop -= e. wheelDeltaY; 
  preventDefault(e);
}
4
Nebril

mon plugin jQuery:

$('.child').dontScrollParent();

$.fn.dontScrollParent = function()
{
    this.bind('mousewheel DOMMouseScroll',function(e)
    {
        var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail;

        if (delta > 0 && $(this).scrollTop() <= 0)
            return false;
        if (delta < 0 && $(this).scrollTop() >= this.scrollHeight - $(this).height())
            return false;

        return true;
    });
}
3
psycho brm

C'est comme ça que j'ai résolu le problème:

J'appelle le suivant quand j'ouvre le popup:

$('body').css('overflow','hidden');

Puis, quand je ferme le popup, j'appelle ça:

$('body').css('overflow','auto');

Le popup est censé être modal, donc aucune interaction n'est requise avec le corps sous-jacent

Fonctionne assez bien

1

Apparemment, vous pouvez définir overflow:hidden pour empêcher le défilement . Je ne sais pas comment ça se passerait si la doc avait déjà défilé. Je suis aussi sur un ordinateur portable sans souris, donc pas de test de roue scrolly pour moi ce soir :-) Cela vaut probablement le coup.

0
Dan F

Voici ce que je fais:

  $('.noscroll').on('DOMMouseScroll mousewheel', function(ev) {
     var prevent = function() {
         ev.stopPropagation();
         ev.preventDefault();
         ev.returnValue = false;
         return false;
     }
     return prevent();
  }); 

violon de démonstration

Utilisez CSS overflow:hidden pour masquer la barre de défilement, car cela ne fera rien s’ils le font glisser.

Fonctionne sur plusieurs navigateurs

0
parliament

Je voudrais ajouter un peu de code mis à jour que j'ai trouvé pour fonctionner mieux:

var yourElement = $('.my-element');

yourElement.on('scroll mousewheel wheel DOMMouseScroll', function (e) {
    var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail;

    if (delta > 0 && $(this).scrollTop() <= 0)
        return false;
    if (delta < 0 && $(this).scrollTop() >= this.scrollHeight - $(this).outerHeight())
        return false;

    return true;
});

La différence entre celle-ci et celle déjà mentionnée ci-dessus réside dans l'ajout de plus d'événements et l'utilisation de outerHeight () au lieu de height () pour éviter le crash si l'élément a un remplissage!

0
Aleksandar Ivanov

Nouveau web dev ici. Cela a fonctionné comme un charme pour moi à la fois sur IE et Chrome.

static preventScrollPropagation(e: HTMLElement) {
    e.onmousewheel = (ev) => {
        var preventScroll = false;
        var isScrollingDown = ev.wheelDelta < 0;
        if (isScrollingDown) {
            var isAtBottom = e.scrollTop + e.clientHeight == e.scrollHeight;
            if (isAtBottom) {
                preventScroll = true;
            }
        } else {
            var isAtTop = e.scrollTop == 0;
            if (isAtTop) {
                preventScroll = true;
            }
        }
        if (preventScroll) {
            ev.preventDefault();
        }
    }
}

Ne laissez pas le nombre de lignes vous tromper, c'est assez simple - juste un peu prolixe pour la lisibilité (code auto-documentant ftw right?)

0
Vivek Maharajh

vous pouvez essayer le volet jscroll dans l’iframe pour remplacer le défilement par défaut. 

http://www.kelvinluck.com/assets/jquery/jScrollPane/jScrollPane.html

Je ne suis pas sûr, mais essayez

0
adardesign

À partir de 2018, e.preventDefault est suffisant.

$('.elementClass').on("scroll", function(e){
    e.preventDefault();
 }); 

Cela empêchera le défilement vers le parent.

0
Must Keem J
$('.scrollable').on('DOMMouseScroll mousewheel', function (e) {
    var up = false;
    if (e.originalEvent) {
        if (e.originalEvent.wheelDelta) up = e.originalEvent.wheelDelta / -1 < 0;
        if (e.originalEvent.deltaY) up = e.originalEvent.deltaY < 0;
        if (e.originalEvent.detail) up = e.originalEvent.detail < 0;
    }

    var prevent = function () {
        e.stopPropagation();
        e.preventDefault();
        e.returnValue = false;
        return false;
    }

    if (!up && this.scrollHeight <= $(this).innerHeight() + this.scrollTop + 1) {
        return prevent();
    } else if (up && 0 >= this.scrollTop - 1) {
        return prevent();
    }
});
0
Roland Soós