242 votes

Empêcher le défilement de l'élément parent?

J'ai un peu "flottant boîte à outils" - un div avec position:fixed; overflow:auto. Fonctionne très bien.

Mais lorsque le défilement à l'intérieur de cette zone (avec la molette de la souris) et atteindre le bas OU le haut, le parent de l'élément "prend en charge" le "défilement demande" : Le document derrière la boîte à outils des parchemins.
- Ce qui est ennuyeux, et pas ce que l'utilisateur "invité".

Je suis à l'aide de jQuery et thoght je pourrais arrêter ce comportement avec l'événement.stoppropagation():
$("#toolBox").scroll( function(event){ event.stoppropagation() });

Il le fait entrer la fonction, mais encore, la propagation se produit de toute façon (le document manuscrits)
- Il est étonnamment difficile à la recherche de ce sujet (et Google), donc je dois demander:
Comment prévenir la propagation de l' / bouillonnement de la de défilement de l'événement ?

Edit:
Solution de travail grâce à amustill (et Brandon Aaron, pour la molette de la souris-plugin ici:
https://github.com/brandonaaron/jquery-mousewheel/raw/master/jquery.mousewheel.js

$(".ToolPage").bind('mousewheel', function(e, d)  
    var t = $(this);
    if (d > 0 && t.scrollTop() === 0) {
        e.preventDefault();
    }
    else {
        if (d < 0 && (t.scrollTop() == t.get(0).scrollHeight - t.innerHeight())) {
            e.preventDefault();
        }
    }
});

177voto

Troy Alford Points 8676

Je suis l'ajout de cette réponse pour l'exhaustivité parce que l'on a accepté la réponse de @amustill ne pas résoudre correctement le problème dans Internet Explorer. Veuillez voir les commentaires dans mon premier post pour plus de détails. En outre, cette solution ne nécessite pas de plugins uniquement jQuery.

En essence, le code fonctionne, par la manipulation de l' mousewheel événement. Chaque événement contient un wheelDelta égal au nombre de px qu'il va déplacer la zone déroulante. Si cette valeur est >0, alors nous sommes défilement up. Si l' wheelDelta est <0 puis nous sommes défilement down.

FireFox: FireFox utilise DOMMouseScroll que l'événement, et remplit originalEvent.detail, dont +/- est inversée par rapport à ce qui est décrit ci-dessus. Il revient généralement à des intervalles d' 3, tandis que les autres navigateurs de retour de défilement dans les intervalles de l' 120 (au moins sur ma machine). Pour corriger, il nous suffit de le détecter et de le multiplier par -40 à se normaliser.

@amustill la réponse de travaux par voie d'annulation de l'événement, si l' <div>s'zone avec défilement est déjà au haut ou le bas à la position maximale. Toutefois, Internet Explorer ignore l'annulation d'un événement dans les situations où l' delta est plus grand que le reste de défilement de l'espace.

En d'autres termes, si vous avez un 200px haut <div> contenant 500px de contenu défilant, et le courant scrollTop est 400, mousewheel événement qui indique au navigateur pour faire défiler 120px supplémentaires se traduira par l' <div> et de la <body> de défilement, car 400 + 120 > 500.

Donc, pour résoudre le problème, nous devons faire quelque chose de différent, comme indiqué ci-dessous:

La condition d' jQuery code est:

$(document).on('DOMMouseScroll mousewheel', '.Scrollable', function(ev) {
    var $this = $(this),
        scrollTop = this.scrollTop,
        scrollHeight = this.scrollHeight,
        height = $this.height(),
        delta = (ev.type == 'DOMMouseScroll' ?
            ev.originalEvent.detail * -40 :
            ev.originalEvent.wheelDelta),
        up = delta > 0;

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

    if (!up && -delta > scrollHeight - height - scrollTop) {
        // Scrolling down, but this will take us past the bottom.
        $this.scrollTop(scrollHeight);
        return prevent();
    } else if (up && delta > scrollTop) {
        // Scrolling up, but this will take us past the top.
        $this.scrollTop(0);
        return prevent();
    }
});

En essence, ce code annule toute défilement événement qui permettrait de créer les indésirables bord, puis utilise jQuery pour définir l' scrollTop de la <div> , soit la valeur minimale ou maximale, selon la direction dans laquelle le mousewheel événement a été demandé.

Parce que l'événement est annulé entièrement dans les deux cas, il ne se propage à l' body à tous, et donc de résoudre le problème sous IE, ainsi que tous les autres navigateurs.

J'ai également mis en place un exemple de travail sur jsFiddle.

45voto

amustill Points 3234

C'est possible avec l'utilisation du plugin Mousewheel de Brandon Aaron.

Voici une démo: http://jsbin.com/ixura3/3

28voto

ghaxx Points 424

Je sais que c'est une question assez ancienne, mais comme c'est l'un des meilleurs résultats de Google ... j'ai dû annuler en quelque sorte le défilement de scroll 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);
}
 

19voto

dOxxx Points 1110

Pour AngularJS, j'ai défini la directive suivante:

 module.directive('isolateScrolling', function () {
  return {
    restrict: 'A',
    link: function (scope, element, attr) {
      element.bind('mousewheel', function (e) {
        if ((e.deltaY > 0 && this.clientHeight + this.scrollTop == this.scrollHeight) ||
            (e.deltaY < 0 && this.scrollTop == 0)) {
          e.stopPropagation();
          e.preventDefault();
          return false;
        }

        return true;
      });
    }
  };
});
 

Et puis l'a ajouté à l'élément scrollable (le menu déroulant ul):

 <div class="dropdown">
  <button type="button" class="btn dropdown-toggle">Rename <span class="caret"></span></button>
  <ul class="dropdown-menu" isolate-scrolling>
    <li ng-repeat="s in savedSettings | objectToArray | orderBy:'name' track by s.name">
      <a ng-click="renameSettings(s.name)">{{s.name}}</a>
    </li>
  </ul>
</div>
 

Seulement testé sur Chrome. Certains hacks sont probablement nécessaires pour différents noms d’événement et pour accéder à la position de défilement des éléments et au delta de la molette de la souris sur les autres navigateurs.

9voto

Bohdan Points 154

En variante, pour éviter les problèmes de performance avec scroll ou mousewheel gestion, vous pouvez utiliser le code suivant:

css:

 body.noscroll {
    overflow: hidden;
}
.scrollable {
    max-height: 200px;
    overflow-y: scroll;
    border: 1px solid #ccc;
}
 

html:

 <div class="scrollable">
...A bunch of items to make the div scroll...
</div>
...A bunch of text to make the body scroll...
 

js:

 var $document = $(document),
    $body = $('body'),
    $scrolable = $('.scrollable');

$scrolable.on({
          'mouseenter': function () {
            // add hack class to prevent workspace scroll when scroll outside
            $body.addClass('noscroll');
          },
          'mouseleave': function () {
            // remove hack class to allow scroll
            $body.removeClass('noscroll');
          }
        });
 

Exemple de travail: http://jsbin.com/damuwinarata/4

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X