¿Evitar el desplazamiento del elemento padre cuando la posición de desplazamiento del elemento interior alcanza la parte superior / inferior?


Tengo una pequeña "caja de herramientas flotante" - un div con position:fixed; overflow:auto. Funciona bien.

Pero cuando se desplaza dentro de esa caja (con la rueda del ratón) y llega a la parte inferior O superior, el elemento padre "se hace cargo" de la "solicitud de desplazamiento" : El documento detrás de la caja de herramientas se desplaza.
- Que es molesto y no lo que el usuario "pidió".

Estoy usando jQuery y pensé que podría detener este comportamiento con event.stoppropagation():
$("#toolBox").scroll( function(event){ event.stoppropagation() });

Ingresa la función, pero aún así, la propagación ocurre de todos modos (los scrolls del documento)
- Es sorprendentemente difícil buscar este tema en SO (y Google), así que tengo que preguntar:
¿Cómo evitar la propagación / burbujeo del evento de desplazamiento ?

Editar:
Solución de trabajo gracias a amustill (y Brandon Aaron para el mousewheel-plugin here:
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();
        }
    }
});
Author: Pandaiolo, 2011-04-27

29 answers

Es posible con el uso de Brandon Aaron's Mousewheel plugin.

Aquí hay una demostración: http://jsbin.com/jivutakama/edit?html,js, output

 37
Author: amustill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-01 22:23:40

Estoy agregando esta respuesta para completar porque la respuesta aceptada por @amustill no resuelve correctamente el problema en Internet Explorer. Por favor, vea los comentarios en mi post original para más detalles. Además, esta solución no requiere ningún plugin - solo jQuery.

En esencia, el código funciona manejando el evento mousewheel. Cada uno de estos eventos contiene un wheelDelta igual al número de px al que va a mover el área desplazable. Si este valor es >0, entonces estamos desplazándonos up. Si el wheelDelta es <0 entonces estamos desplazándonos down.

FireFox : FireFox usa DOMMouseScroll como evento, y rellena originalEvent.detail, cuyo +/- se invierte de lo descrito anteriormente. Generalmente devuelve intervalos de 3, mientras que otros navegadores devuelven el desplazamiento en intervalos de 120 (al menos en mi máquina). Para corregir, simplemente lo detectamos y multiplicamos por -40 para normalizar.

@la respuesta de amutill funciona cancelando el evento si el área desplazable de <div> ya está en la posición máxima superior o inferior. Sin embargo, Internet Explorer no tiene en cuenta el evento cancelado en situaciones en las que el delta es mayor que el espacio de desplazamiento restante.

En otras palabras, si tiene un 200px alto <div> que contiene 500px de contenido desplazable, y el actual scrollTop es 400, un evento mousewheel que le dice al navegador que se desplace 120px más resultará tanto en el <div> como en el <body> desplazamiento, porque 400 + 120 > 500.

Entonces, para resolver el problema, tenemos que hacer algo ligeramente diferente, como se muestra a continuación:

El código requerido jQuery es:

$(document).on('DOMMouseScroll mousewheel', '.Scrollable', function(ev) {
    var $this = $(this),
        scrollTop = this.scrollTop,
        scrollHeight = this.scrollHeight,
        height = $this.innerHeight(),
        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 esencia, este código cancela cualquier evento de desplazamiento que crearía la condición de borde no deseada, luego usa jQuery para establecer el scrollTop del <div> en el valor máximo o mínimo, dependiendo de la dirección que el evento mousewheel estuviera solicitando.

Porque el evento se cancela enteramente en cualquier caso, nunca se propaga a la body en absoluto, y por lo tanto resuelve el problema en IE, así como todos los otros navegadores.

También he puesto un ejemplo de trabajo en jsFiddle.

 165
Author: Troy Alford,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:01

Sé que es una pregunta bastante antigua, pero ya que este es uno de los mejores resultados en Google... Tuve que cancelar de alguna manera scroll bubbling sin jQuery y este código funciona para mí:

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);
}
 19
Author: Nebril,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-20 11:58:05

EDITAR: CodePen ejemplo

Para AngularJS, definí la siguiente directiva:

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

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

Y luego lo agregó al elemento desplazable (el menú desplegable 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>

Probado en Chrome y Firefox. Desplazamiento suave de Chrome derrota a este hack cuando un gran movimiento de la rueda del ratón se hace cerca (pero no en) la parte superior o inferior de la región de desplazamiento.

 17
Author: dOxxx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-20 14:19:22

Hay toneladas de preguntas como esta por ahí, con muchas respuestas, pero no pude encontrar una solución satisfactoria que no involucrara eventos, scripts, plugins, etc. Quería mantenerlo recto en HTML y CSS. Finalmente encontré una solución que funcionó, aunque implicaba reestructurar el marcado para romper la cadena de eventos.


1. Problema básico

La entrada de desplazamiento (es decir: mousewheel) aplicada al elemento modal se derramará en un elemento antepasado y scroll it in the same direction, if some such element is scrollable:

(Todos los ejemplos están diseñados para ser vistos en resoluciones de escritorio)

Https://jsfiddle.net/ybkbg26c/5 /

HTML:

<div id="parent">
  <div id="modal">
    This text is pretty long here.  Hope fully, we will get some scroll bars.
  </div>
</div>

CSS:

#modal {
  position: absolute;
  height: 100px;
  width: 100px;
  top: 20%;
  left: 20%;
  overflow-y: scroll;
}
#parent {
  height: 4000px;
}

2. Sin desplazamiento padre en desplazamiento modal

La razón por la que el ancestro termina desplazándose es porque el evento de desplazamiento se burbujas y algún elemento en la cadena es capaz de manejarlo. Una manera de parar eso es asegurarse de que ninguno de los elementos de la cadena sabe cómo manejar el pergamino. En términos de nuestro ejemplo, podemos refactorizar el árbol para mover el modal fuera del elemento padre. Por razones oscuras, no es suficiente mantener el padre y los hermanos DOM modales; el padre debe estar envuelto por otro elemento que establezca un nuevo contexto de apilamiento. Una envoltura absolutamente posicionada alrededor del padre puede hacer el truco.

El resultado que obtenemos es que mientras el modal reciba el scroll event, el evento no burbujeará en el elemento "padre".

Normalmente debería ser posible rediseñar el árbol DOM para soportar este comportamiento sin afectar lo que ve el usuario final.

Https://jsfiddle.net/0bqq31Lv/3 /

HTML:

<div id="context">
  <div id="parent">
  </div>
</div>
<div id="modal">
  This text is pretty long here.  Hope fully, we will get some scroll bars.
</div>

CSS (solo nuevo):

#context {
  position: absolute;
  overflow-y: scroll;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

3. No hay desplazamiento en ninguna parte excepto en modal mientras está arriba

La solución anterior aún permite que el padre reciba eventos de desplazamiento, siempre y cuando no interceptado por la ventana modal (es decir, si se activa por la rueda del ratón mientras el cursor no está sobre el modal). Esto a veces es indeseable y es posible que desee prohibir todo desplazamiento en segundo plano mientras el modal está arriba. Para hacer eso, necesitamos insertar un contexto de apilamiento adicional que abarque toda la vista detrás del modal. Podemos hacer eso mostrando una superposición absolutamente posicionada, que puede ser completamente transparente si es necesario (pero no visibility:hidden).

Https://jsfiddle.net/0bqq31Lv/2 /

HTML:

<div id="context">
  <div id="parent">
  </div>
</div>
<div id="overlay">  
</div>
<div id="modal">
  This text is pretty long here.  Hope fully, we will get some scroll bars.
</div>

CSS (nuevo encima de #2):

#overlay {
  background-color: transparent;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}
 9
Author: Daniel S.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-24 10:12:17

Directiva angular JS

Tuve que envolver una directiva angular. El siguiente es un Mashup de las otras respuestas aquí. probado en Chrome e Internet Explorer 11.

var app = angular.module('myApp');

app.directive("preventParentScroll", function () {
    return {
        restrict: "A",
        scope: false,
        link: function (scope, elm, attr) {
            elm.bind('mousewheel', onMouseWheel);
            function onMouseWheel(e) {
                elm[0].scrollTop -= (e.wheelDeltaY || (e.originalEvent && (e.originalEvent.wheelDeltaY || e.originalEvent.wheelDelta)) || e.wheelDelta || 0);
                e.stopPropagation();
                e.preventDefault();
                e.returnValue = false;
            }
        }
    }
});

Uso

<div prevent-parent-scroll>
    ...
</div>

Espera que esto ayude a la siguiente persona que llegue aquí desde una búsqueda en Google.

 9
Author: Jossef Harush,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-15 11:37:55

Como variante, para evitar problemas de rendimiento con el manejo de scroll o mousewheel, puede usar código como el siguiente:

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

Ejemplo de trabajo: http://jsbin.com/damuwinarata/4

 8
Author: Bohdan Lyzanets,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-10 14:33:52

Usando las propiedades de desplazamiento del elemento nativo con el valor delta del complemento mousewheel:

$elem.on('mousewheel', function (e, delta) {
    // Restricts mouse scrolling to the scrolling range of this element.
    if (
        this.scrollTop < 1 && delta > 0 ||
        (this.clientHeight + this.scrollTop) === this.scrollHeight && delta < 0
    ) {
        e.preventDefault();
    }
});
 7
Author: Pete B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-19 12:55:34

Todas las soluciones dadas en este hilo no mencionan una forma existente - y nativa - de resolver este problema sin reordenar el DOM y/o usar trucos de prevención de eventos. Pero hay una buena razón: esta manera es propietaria - y disponible en la plataforma web de MS solamente. Citando MSDN:

-ms-scroll-encadenamiento propiedad: especifica el comportamiento de desplazamiento que se produce cuando un usuario alcanza el límite de desplazamiento durante una manipulación. Valores de propiedad:

Encadenado - valor Inicial. El elemento padre desplazable más cercano comienza a desplazarse cuando el usuario alcanza un límite de desplazamiento durante una manipulación. No se muestra ningún efecto de rebote.

None - Se muestra un efecto de rebote cuando el usuario alcanza un límite de desplazamiento durante una manipulación.

Concedido, esta propiedad es soportada solo en IE10+/Edge. Aun así, aquí hay un cita reveladora:

Para darte una idea de lo popular que es prevenir el desplazamiento el encadenamiento puede ser, de acuerdo con mi búsqueda rápida http-archive " - ms-scroll-chaining: ninguno" se utiliza en el 0.4% de las 300K páginas principales a pesar de estar limitado en funcionalidad y solo compatible con IE / Edge.

Y ahora buenas noticias, todo el mundo! A partir de Chrome 63, finalmente tenemos una cura nativa para las plataformas basadas en parpadeo también-y eso es tanto Chrome (obviamente) y Android WebView (pronto).

Citando el artículo introductorio:

El la propiedad overscroll-behavior es una nueva característica CSS que controla el comportamiento de lo que sucede cuando se desplaza sobre un contenedor (incluyendo la propia página). Puede usarlo para cancelar el encadenamiento de desplazamiento, desactivar / personalizar la acción pull-to-refresh, desactivar rubberbanding efectos en iOS (cuando Safari implementa el comportamiento overscroll), y más.[...]

La propiedad toma tres valores posibles:

Auto Predeterminado. Los pergaminos que se originan en el elemento pueden propagar a elementos antecesores.

Contain - evita el encadenamiento de desplazamiento. Los pergaminos no propagar a los antepasados, pero se muestran los efectos locales dentro del nodo. Por ejemplo, el efecto de brillo de overscroll en Android o el efecto rubberbanding en iOS que notifica al usuario cuando límite de desplazamiento. Nota: usando overscroll-behavior: contain en el html element evita las acciones de navegación de sobre-desplazamiento.

None - igual que contain pero también evita los efectos de sobreescritura dentro del propio nodo (por ejemplo, brillo de sobreescritura de Android o rubberbanding de iOS).

[...] La mejor parte es que el uso del comportamiento de sobre-desplazamiento no afectar el rendimiento de la página como los hacks mencionados en la introducción!

Aquí está esto característica en acción. Y aquí está correspondiente Documento del Módulo CSS.

ACTUALIZACIÓN: Firefox, desde la versión 59, se ha unido al club, y MS Edge es se espera implementar esta característica en la versión 18. Aquí está el correspondiente caniusage.

 7
Author: raina77ow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-19 15:33:23

En caso de que alguien todavía esté buscando una solución para esto, el siguiente complemento hace el trabajo http://mohammadyounes.github.io/jquery-scrollLock /

Aborda completamente el problema de bloquear el desplazamiento de la rueda del ratón dentro de un contenedor dado, evitando que se propague al elemento padre.

No cambia la velocidad de desplazamiento de la rueda, la experiencia del usuario no se verá afectada. y obtiene el mismo comportamiento independientemente de la velocidad de desplazamiento vertical de la rueda del ratón del sistema operativo (En Windows se puede configurar en una pantalla o una línea de hasta 100 líneas por muesca).

Demo: http://mohammadyounes.github.io/jquery-scrollLock/example /

Fuente: https://github.com/MohammadYounes/jquery-scrollLock

 6
Author: MK.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-24 12:47:17

Aquí hay una versión simple de JavaScript:

function scroll(e) {
  var delta = (e.type === "mousewheel") ? e.wheelDelta : e.detail * -40;
  if (delta < 0 && (this.scrollHeight - this.offsetHeight - this.scrollTop) <= 0) {
    this.scrollTop = this.scrollHeight;
    e.preventDefault();
  } else if (delta > 0 && delta > this.scrollTop) {
    this.scrollTop = 0;
    e.preventDefault();
  }
}
document.querySelectorAll(".scroller").addEventListener("mousewheel", scroll);
document.querySelectorAll(".scroller").addEventListener("DOMMouseScroll", scroll);
 6
Author: silverwind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-19 00:01:13

La respuesta de Amutill como manejador de nocaut:

ko.bindingHandlers.preventParentScroll = {
    init: function (element, valueAccessor, allBindingsAccessor, context) {
        $(element).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();
                }
            }
        });
    }
};
 4
Author: mhu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-18 14:45:23

Esto realmente funciona en AngularJS. Probado en Chrome y Firefox.

.directive('stopScroll', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            element.bind('mousewheel', function (e) {
                var $this = $(this),
                    scrollTop = this.scrollTop,
                    scrollHeight = this.scrollHeight,
                    height = $this.height(),
                    delta = (e.type == 'DOMMouseScroll' ?
                    e.originalEvent.detail * -40 :
                        e.originalEvent.wheelDelta),
                    up = delta > 0;

                var prevent = function() {
                    e.stopPropagation();
                    e.preventDefault();
                    e.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();
                }
            });
        }
    };
})
 4
Author: Remot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-24 19:32:59

El método anterior no es tan natural, después de buscar en Google encuentro una solución más agradable , y no hay necesidad de jQuery. ver [1] y demo [2].

  var element = document.getElementById('uf-notice-ul');

  var isMacWebkit = (navigator.userAgent.indexOf("Macintosh") !== -1 &&
    navigator.userAgent.indexOf("WebKit") !== -1);
  var isFirefox = (navigator.userAgent.indexOf("firefox") !== -1);

  element.onwheel = wheelHandler; // Future browsers
  element.onmousewheel = wheelHandler; // Most current browsers
  if (isFirefox) {
    element.scrollTop = 0;
    element.addEventListener("DOMMouseScroll", wheelHandler, false);
  }
  // prevent from scrolling parrent elements
  function wheelHandler(event) {
    var e = event || window.event; // Standard or IE event object

    // Extract the amount of rotation from the event object, looking
    // for properties of a wheel event object, a mousewheel event object 
    // (in both its 2D and 1D forms), and the Firefox DOMMouseScroll event.
    // Scale the deltas so that one "click" toward the screen is 30 pixels.
    // If future browsers fire both "wheel" and "mousewheel" for the same
    // event, we'll end up double-counting it here. Hopefully, however,
    // cancelling the wheel event will prevent generation of mousewheel.
    var deltaX = e.deltaX * -30 || // wheel event
      e.wheelDeltaX / 4 || // mousewheel
      0; // property not defined
    var deltaY = e.deltaY * -30 || // wheel event
      e.wheelDeltaY / 4 || // mousewheel event in Webkit
      (e.wheelDeltaY === undefined && // if there is no 2D property then 
        e.wheelDelta / 4) || // use the 1D wheel property
      e.detail * -10 || // Firefox DOMMouseScroll event
      0; // property not defined

    // Most browsers generate one event with delta 120 per mousewheel click.
    // On Macs, however, the mousewheels seem to be velocity-sensitive and
    // the delta values are often larger multiples of 120, at 
    // least with the Apple Mouse. Use browser-testing to defeat this.
    if (isMacWebkit) {
      deltaX /= 30;
      deltaY /= 30;
    }
    e.currentTarget.scrollTop -= deltaY;
    // If we ever get a mousewheel or wheel event in (a future version of)
    // Firefox, then we don't need DOMMouseScroll anymore.
    if (isFirefox && e.type !== "DOMMouseScroll") {
      element.removeEventListener("DOMMouseScroll", wheelHandler, false);
    }
    // Don't let this event bubble. Prevent any default action.
    // This stops the browser from using the mousewheel event to scroll
    // the document. Hopefully calling preventDefault() on a wheel event
    // will also prevent the generation of a mousewheel event for the
    // same rotation.
    if (e.preventDefault) e.preventDefault();
    if (e.stopPropagation) e.stopPropagation();
    e.cancelBubble = true; // IE events
    e.returnValue = false; // IE events
    return false;
  }

[1] https://dimakuzmich.wordpress.com/2013/07/16/prevent-scrolling-of-parent-element-with-javascript/

[2] http://jsfiddle.net/dima_k/5mPkB/1/

 3
Author: jinwei,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-24 09:44:20

Para aquellos que usan MooTools, aquí está el código equivalente:

            'mousewheel': function(event){
            var height = this.getSize().y;
            height -= 2;    // Not sure why I need this bodge
            if ((this.scrollTop === (this.scrollHeight - height) && event.wheel < 0) || 
                (this.scrollTop === 0 && event.wheel > 0)) {
                event.preventDefault();
            }

Tenga en cuenta que yo, como algunos otros, tuve que ajustar un valor por un par de px, que es lo que la altura -= 2 es para.

Básicamente la principal diferencia es que en MooTools, la información delta viene de event.rueda en lugar de un parámetro adicional pasado al evento.

Además, tuve problemas si enlazaba este código a algo (event.objetivo.scrollHeight para una función enlazada no es igual a esto.Altura de desplazamiento para a no vinculado)

Espero que esto ayude a alguien tanto como este post me ayudó a mí;)

 1
Author: Clive Galway,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-11 12:31:50

Mi plugin de 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;
    });
}
 1
Author: psycho brm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-14 14:28:28

Nuevo desarrollador web aquí. Esto funcionó como un encanto para mí en IE y 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();
        }
    }
}

No dejes que el número de líneas te engañe, es bastante simple - solo un poco detallado para la legibilidad (código de auto-documentación ftw correcto?)

También debo mencionar que el lenguaje aquí es Manuscrito, pero como siempre, es sencillo convertir a JS.

 1
Author: Vivek Maharajh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-25 16:52:25

He seleccionado esto de la biblioteca elegida: https://github.com/harvesthq/chosen/blob/master/coffee/chosen.jquery.coffee

function preventParentScroll(evt) {
    var delta = evt.deltaY || -evt.wheelDelta || (evt && evt.detail)
    if (delta) {
        evt.preventDefault()
        if (evt.type ==  'DOMMouseScroll') {
            delta = delta * 40  
        }
        fakeTable.scrollTop = delta + fakeTable.scrollTop
    }
}
var el = document.getElementById('some-id')
el.addEventListener('mousewheel', preventParentScroll)
el.addEventListener('DOMMouseScroll', preventParentScroll)

Esto funciona para mí.

 1
Author: Drew LeSueur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-27 10:42:55

Odio publicar necro, pero estaba buscando esto para MooTools y este fue el primero que surgió. El ejemplo original de MooTools funcionaría con desplazamiento hacia arriba, pero no hacia abajo, así que decidí escribir este.


var stopScroll = function (e) {
    var scrollTo = null;
    if (e.event.type === 'mousewheel') {
        scrollTo = (e.event.wheelDelta * -1);
    } else if (e.event.type === 'DOMMouseScroll') {
        scrollTo = 40 * e.event.detail;
    }
    if (scrollTo) {
        e.preventDefault();
        this.scrollTo(0, scrollTo + this.scrollTop);
    }
    return false;
};

Uso:

(function)($){
    window.addEvent('domready', function(){
        $$('.scrollable').addEvents({
             'mousewheel': stopScroll,
             'DOMMouseScroll': stopScroll
        });
    });
})(document.id);
 0
Author: fyrye,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-01 21:04:08

Plugin jQuery con emular desplazamiento natural para Internet Explorer

  $.fn.mousewheelStopPropagation = function(options) {
    options = $.extend({
        // defaults
        wheelstop: null // Function
        }, options);

    // Compatibilities
    var isMsIE = ('Microsoft Internet Explorer' === navigator.appName);
    var docElt = document.documentElement,
        mousewheelEventName = 'mousewheel';
    if('onmousewheel' in docElt) {
        mousewheelEventName = 'mousewheel';
    } else if('onwheel' in docElt) {
        mousewheelEventName = 'wheel';
    } else if('DOMMouseScroll' in docElt) {
        mousewheelEventName = 'DOMMouseScroll';
    }
    if(!mousewheelEventName) { return this; }

    function mousewheelPrevent(event) {
        event.preventDefault();
        event.stopPropagation();
        if('function' === typeof options.wheelstop) {
            options.wheelstop(event);
        }
    }

    return this.each(function() {
        var _this = this,
            $this = $(_this);
        $this.on(mousewheelEventName, function(event) {
            var origiEvent = event.originalEvent;
            var scrollTop = _this.scrollTop,
                scrollMax = _this.scrollHeight - $this.outerHeight(),
                delta = -origiEvent.wheelDelta;
            if(isNaN(delta)) {
                delta = origiEvent.deltaY;
            }
            var scrollUp = delta < 0;
            if((scrollUp && scrollTop <= 0) || (!scrollUp && scrollTop >= scrollMax)) {
                mousewheelPrevent(event);
            } else if(isMsIE) {
                // Fix Internet Explorer and emulate natural scrolling
                var animOpt = { duration:200, easing:'linear' };
                if(scrollUp && -delta > scrollTop) {
                    $this.stop(true).animate({ scrollTop:0 }, animOpt);
                    mousewheelPrevent(event);
                } else if(!scrollUp && delta > scrollMax - scrollTop) {
                    $this.stop(true).animate({ scrollTop:scrollMax }, animOpt);
                    mousewheelPrevent(event);
                }
            }
        });
    });
};

Https://github.com/basselin/jquery-mousewheel-stop-propagation/blob/master/mousewheelStopPropagation.js

 0
Author: B.Asselin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-02 10:48:41

La mejor solución que pude encontrar fue escuchar el evento scroll en la ventana y establecer el scrollTop al scrollTop anterior si el div hijo era visible.

prevScrollPos = 0
$(window).scroll (ev) ->
    if $('#mydiv').is(':visible')
        document.body.scrollTop = prevScrollPos
    else
        prevScrollPos = document.body.scrollTop

Hay un parpadeo en el fondo del div hijo si dispara muchos eventos de desplazamiento, por lo que esto podría ser ajustado, pero apenas se nota y fue suficiente para mi caso de uso.

 0
Author: GijsjanB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-08 09:32:37

Tengo una situación similar y así es como la resolví:
Todos mis elementos desplazables obtienen la clase desplazable.

$(document).on('wheel', '.scrollable', function(evt) {
  var offsetTop = this.scrollTop + parseInt(evt.originalEvent.deltaY, 10);
  var offsetBottom = this.scrollHeight - this.getBoundingClientRect().height - offsetTop;

  if (offsetTop < 0 || offsetBottom < 0) {
    evt.preventDefault();
  } else {
    evt.stopImmediatePropagation();
  }
});

stopImmediatePropagation () se asegura de no desplazar el área desplazable principal desde el área secundaria desplazable.

Aquí está una implementación JS vainilla de la misma: http://jsbin.com/lugim/2/edit?js, output

 0
Author: user3259967,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-21 15:06:49

No use overflow: hidden; en body. Se desplaza automáticamente todo a la parte superior. No hay necesidad de JavaScript tampoco. Haga uso de overflow: auto;:

Estructura HTML

<div class="overlay">
    <div class="overlay-content"></div>
</div>

<div class="background-content">
    lengthy content here
</div>

Estilo

.overlay{
    position: fixed;
    top: 0px;
    left: 0px;
    right: 0px;
    bottom: 0px;
    background-color: rgba(0, 0, 0, 0.8);

    .overlay-content {
        height: 100%;
        overflow: scroll;
    }
}

.background-content{
    height: 100%;
    overflow: auto;
}

Juega con la demo aquí.

 0
Author: Luxiyalu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-24 11:11:07

Mira El código de Leland Kwong.

La idea básica es enlazar el evento wheeling al elemento hijo, y luego usar la propiedad nativa de javascript scrollHeight y la propiedad jquery outerHeight del elemento hijo para detectar el final del desplazamiento, sobre el cual return false al evento wheeling para evitar cualquier desplazamiento.

var scrollableDist,curScrollPos,wheelEvent,dY;
$('#child-element').on('wheel', function(e){
  scrollableDist = $(this)[0].scrollHeight - $(this).outerHeight();
  curScrollPos = $(this).scrollTop();
  wheelEvent = e.originalEvent;
  dY = wheelEvent.deltaY;
  if ((dY>0 && curScrollPos >= scrollableDist) ||
      (dY<0 && curScrollPos <= 0)) {
    return false;
  }
});
 0
Author: Vic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-28 13:44:21

También hay un truco divertido para bloquear el scrollTop del padre cuando el ratón se desplaza sobre un elemento desplazable. De esta manera usted no tiene que implementar su propio desplazamiento de la rueda.

Aquí hay un ejemplo para evitar el desplazamiento del documento, pero se puede ajustar para cualquier elemento.

scrollable.mouseenter(function ()
{
  var scroll = $(document).scrollTop();
  $(document).on('scroll.trap', function ()
  {
    if ($(document).scrollTop() != scroll) $(document).scrollTop(scroll);
  });
});

scrollable.mouseleave(function ()
{
  $(document).off('scroll.trap');
});
 0
Author: Sebastian Nowak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-15 16:34:15

M. K. ofreció un gran plugin en su respuesta. Plugin se puede encontrar aquí. Sin embargo, en aras de la finalización, pensé que sería una buena idea ponerlo juntos en una respuesta para AngularJS.

  1. Comience inyectando la enramada o npm (lo que se prefiera)

    bower install jquery-scrollLock --save
    npm install jquery-scroll-lock --save
    
  2. Añádase la siguiente directiva. Estoy eligiendo agregarlo como un atributo

    (function() {
       'use strict';
    
        angular
           .module('app')
           .directive('isolateScrolling', isolateScrolling);
    
           function isolateScrolling() {
               return {
                   restrict: 'A',
                   link: function(sc, elem, attrs) {
                      $('.scroll-container').scrollLock();
                   }
               }
           }
    })();
    
  3. Y la pieza importante que el plugin no documenta en su sitio web está la estructura HTML que debe seguir.

    <div class="scroll-container locked">
        <div class="scrollable" isolate-scrolling>
             ... whatever ...
        </div>
    </div>
    

El atributo isolate-scrolling debe contener la clase scrollable y todo debe estar dentro de la clase scroll-container o cualquier clase que elija y la clase locked debe estar en cascada.

 0
Author: LOTUSMS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:13

Vale la pena mencionar que con frameworks modernos como ReactJS, AngularJS, VueJS, etc, hay soluciones fáciles para este problema, cuando se trata de elementos de posición fija. Ejemplos de ello son los paneles laterales o los elementos superpuestos.

La técnica se llama un "Portal", lo que significa que uno de los componentes utilizados en la aplicación, sin la necesidad de extraerlo realmente desde donde lo está utilizando, montará sus hijos en la parte inferior del elemento body, fuera del padre que está tratando de evita el desplazamiento.

Tenga en cuenta que no evitará el desplazamiento del elemento body en sí. Puede combinar esta técnica y montar su aplicación en un div de desplazamiento para lograr el resultado esperado.

Ejemplo de implementación de Portal en material-ui de React: https://material-ui-next.com/api/portal /

 0
Author: Pandaiolo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-14 10:14:53

Solución simple con evento mouseweel:

$('.element').bind('mousewheel', function(e, d) {
    console.log(this.scrollTop,this.scrollHeight,this.offsetHeight,d);
    if((this.scrollTop === (this.scrollHeight - this.offsetHeight) && d < 0)
        || (this.scrollTop === 0 && d > 0)) {
        e.preventDefault();
    }
});
 -1
Author: egor.xyz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-05 14:04:02

Puedes probarlo de esta manera:

$('#element').on('shown', function(){ 
   $('body').css('overflow-y', 'hidden');
   $('body').css('margin-left', '-17px');
});

$('#element').on('hide', function(){ 
   $('body').css('overflow-y', 'scroll');
   $('body').css('margin-left', '0px');
});
 -2
Author: Korplex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-11 07:55:07