javascript - tablas - ¿Impide el desplazamiento del elemento principal?
obtener elemento html con javascript (28)
Directiva Angular JS
Tenía que ajustar 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 llega aquí desde una búsqueda en Google.
Tengo una pequeña "caja de herramientas flotante" - un div con position:fixed; overflow:auto
position:fixed; overflow:auto
. Funciona bien
Pero cuando se desplaza dentro de esa casilla (con la rueda del mouse) y alcanza la parte inferior O superior, el elemento principal "toma el control" de la "solicitud de desplazamiento": El documento que se encuentra 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 a la función, pero aún así, la propagación ocurre de todos modos (el documento se desplaza)
- Es sorprendentemente difícil buscar este tema en SO (y Google), así que tengo que preguntar:
¿Cómo prevenir la propagación / burbujeo del evento scroll?
Editar:
Solución de trabajo gracias a amustill (y a Brandon Aaron por el plugin mousewheel aquí:
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();
}
}
});
Aquí hay una versión de JavaScript simple:
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);
Como variante, para evitar problemas de rendimiento con el scroll
o la manipulación de la mousewheel
, puede usar el código 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
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 mouse dentro de un contenedor determinado, lo que impide que se propague al elemento principal.
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 mouse del sistema operativo (en Windows se puede establecer en una pantalla o una línea de hasta 100 líneas por muesca).
Demostración: http://mohammadyounes.github.io/jquery-scrollLock/example/
Es posible con el uso del complemento Brandon Aaron''s Mousewheel .
Aquí hay una demostración: http://jsbin.com/jivutakama/edit?html,js,output
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();
}
});
}
};
})
Estoy agregando esta respuesta para que esté completa porque la respuesta aceptada por @amustill no resuelve el problema correctamente en Internet Explorer . Por favor, vea los comentarios en mi publicación original para más detalles. Además, esta solución no requiere complementos, solo jQuery.
En esencia, el código funciona manejando el evento mousewheel
. Cada evento de este tipo contiene una wheelDelta
igual a la cantidad de px
que moverá el área desplazable. Si este valor es >0
, entonces nos estamos desplazando up
. Si el wheelDelta
es <0
entonces estamos desplazándonos down
.
FireFox : FireFox utiliza DOMMouseScroll
como el evento y completa originalEvent.detail
, cuyo +/-
se invierte de lo descrito anteriormente. Por lo general, devuelve intervalos de 3
, mientras que otros exploradores vuelven a desplazarse en intervalos de 120
(al menos en mi máquina). Para corregirlo, simplemente lo detectamos y multiplicamos por -40
para normalizarlo.
La respuesta de @ amustill funciona cancelando el evento si el área desplazable del <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 más grande que el espacio desplazable restante.
En otras palabras, si tiene un <div>
200px
alto que contiene 500px
de contenido desplazable, y el scrollTop
actual es 400
, un evento mousewheel
que le dice al navegador que se desplace 120px
más resultará en el <div>
y 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 jQuery
requerido 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 deseado, luego usa jQuery para establecer el scrollTop
de <div>
en el valor máximo o mínimo, dependiendo de la dirección que mousewheel
evento mousewheel
.
Debido a que el evento se cancela por completo en cualquier caso, nunca se propaga al body
en absoluto, y por lo tanto resuelve el problema en IE, así como en todos los otros navegadores.
También puse un ejemplo de trabajo en jsFiddle .
Hay un montón de preguntas como esta, con muchas respuestas, pero no pude encontrar una solución satisfactoria que no involucrara eventos, scripts, complementos, etc. Quería mantenerla en línea recta en HTML y CSS. Finalmente encontré una solución que funcionó, aunque implicó reestructurar el marcado para romper la cadena de eventos.
1. Problema básico
La entrada de desplazamiento (es decir, la rueda del mouse) aplicada al elemento modal se extenderá a un elemento ancestro y lo desplazará en la misma dirección, si algún elemento es desplazable:
(Todos los ejemplos están destinados a 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 primario en desplazamiento modal
La razón por la que el ancestro termina desplazándose es porque el evento de desplazamiento burbujea y algún elemento de la cadena puede manejarlo. Una forma de detener esto es asegurarse de que ninguno de los elementos de la cadena sepa cómo manejar el desplazamiento. En términos de nuestro ejemplo, podemos refactorizar el árbol para mover el modal del elemento padre. Por razones oscuras, no es suficiente mantener al padre y a los hermanos DOM modales; el padre debe estar envuelto por otro elemento que establezca un nuevo contexto de apilamiento. Un contenedor absolutamente posicionado alrededor del padre puede hacer el truco.
El resultado que obtenemos es que, siempre que el modal reciba el evento de desplazamiento, el evento no pasará al elemento "principal".
Por lo general, debería ser posible rediseñar el árbol DOM para admitir 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 desplazarse a ningún lado excepto en modo modal mientras está activo
La solución anterior aún le permite al padre recibir eventos de desplazamiento, siempre y cuando no sean interceptados por la ventana modal (es decir, si se desencadena con la rueda del mouse mientras el cursor no está sobre el modal). Esto a veces es indeseable y es posible que deseemos prohibir todo desplazamiento en segundo plano mientras el modal está activo. Para hacer eso, necesitamos insertar un contexto de apilamiento adicional que abarque toda la ventana gráfica detrás del modal. Podemos hacerlo mostrando una superposición totalmente 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 en la parte superior de la n. ° 2):
#overlay {
background-color: transparent;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
Lo solté 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í
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 la cantidad de líneas te engañe, es bastante simple, solo un poco detallado para la legibilidad (código de auto documentación, ¿verdad?)
También debo mencionar que el lenguaje aquí es TypeScript , pero como siempre, es sencillo convertirlo a JS.
Odio publicar necro pero estaba buscando esto para MooTools y este fue el primero que apareció. El ejemplo original de MooTools funcionaría al desplazarse hacia arriba, pero no al desplazarse hacia abajo, así que decidí escribir este.
- MooTools 1.4.5: http://jsfiddle.net/3MzFJ/
- MooTools 1.3.2: http://jsfiddle.net/VhnD4/
- MooTools 1.2.6: http://jsfiddle.net/xWrw4/
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);
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 agregué 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. El desplazamiento suave de Chrome derrota este truco cuando se hace un gran movimiento de la rueda del mouse cerca (pero no en) la parte superior o inferior de la región de desplazamiento.
Para aquellos que usan MooTools, aquí hay un 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 modificar un valor por un par de px, para eso es la altura - = 2.
Básicamente, la principal diferencia es que en MooTools, la información delta proviene de event.wheel en lugar de un parámetro adicional que se pasa al evento.
Además, tuve problemas si ligaba este código a cualquier cosa (event.target.scrollHeight para una función enlazada no es igual a this.scrollHeight para una no vinculada)
Espero que esto ayude a alguien tanto como este post me ayudó;)
Plugin jQuery con emular el 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);
}
}
});
});
};
Sé que es una pregunta bastante antigua, pero dado que este es uno de los mejores resultados en google ... tuve que cancelar de alguna manera el burbujeo de scroll 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);
}
Todas las soluciones proporcionadas en este hilo no mencionan una forma existente (y nativa) de resolver este problema sin reordenar DOM y / o utilizar trucos para evitar eventos. Pero hay una buena razón: de esta manera es patentada, y solo está disponible en la plataforma web de MS. Citando MSDN :
propiedad -ms-scroll-encadenamiento : especifica el comportamiento de desplazamiento que se produce cuando un usuario toca el límite de desplazamiento durante una manipulación. Valores de propiedad:
encadenado - Valor inicial. El elemento principal desplazable más cercano comienza a desplazarse cuando el usuario toca 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 toca un límite de desplazamiento durante una manipulación.
Por supuesto, esta propiedad solo es compatible con IE10 + / Edge. Aún así, aquí hay una cita contundente :
Para darle una idea de lo popular que puede ser prevenir el encadenamiento de desplazamiento, de acuerdo con mi búsqueda rápida de archivo http "-ms-scroll-encadenamiento: ninguno" se usa en 0.4% de las 300,000 páginas principales a pesar de tener una funcionalidad limitada y solo soporte en IE / Edge.
Y ahora buenas noticias, ¡a todos! A partir de Chrome 63, finalmente tenemos una cura nativa para las plataformas basadas en Blink también, y eso es tanto Chrome (obviamente) como Android WebView (pronto).
Citando el artículo introductor :
La propiedad de comportamiento de sobrerrecorrido es una nueva característica de CSS que controla el comportamiento de lo que sucede cuando desplaza en exceso un contenedor (incluida la página misma). Puede usarlo para cancelar el encadenamiento de desplazamiento, deshabilitar / personalizar la acción de pull-to-refresh, deshabilitar los efectos de rubberbanding en iOS (cuando Safari implementa comportamiento overscroll) y más. [...]
La propiedad toma tres valores posibles:
auto - Predeterminado. Los rollos que se originan en el elemento pueden propagarse a elementos ancestrales.
contener - evita el encadenamiento de desplazamiento. Los rollos no se propagan a los antepasados, pero se muestran los efectos locales dentro del nodo. Por ejemplo, el efecto de destello del sobrerrollamiento en Android o el efecto rubberbanding en iOS que notifica al usuario cuando han tocado un límite de desplazamiento. Nota: el uso de overscroll-behavior: contains en el elemento html evita las acciones de navegación de sobredesplotación.
ninguno : lo mismo que contener, pero también previene los efectos de sobrerrecorrido dentro del propio nodo (p. ej., resplandor de desbordamiento de Android o banda de goma de iOS).
[...] ¡ La mejor parte es que el uso de overscroll-behavior no afecta negativamente el rendimiento de la página, como los hacks mencionados en la introducción!
Aquí está esta característica en acción . Y aquí está el documento del Módulo CSS correspondiente.
Usar propiedades de desplazamiento de 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();
}
});
el método anterior no es tan natural, después de buscar en Google encuentro una solución más agradable y no necesito jQuery. ver [1] y demostración [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/
la respuesta de amustill como controlador de knockout:
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();
}
}
});
}
};
mi 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;
});
}
offered a great plugin in his answer. Plugin can be found here . However, for the sake of completion, I thought it''d be a good idea to put it together in one answer for AngularJS.
Start by injecting the bower or npm (whichever is preferred)
bower install jquery-scrollLock --save npm install jquery-scroll-lock --save
Add the following directive. I am choosing to add it as an attribute
(function() { ''use strict''; angular .module(''app'') .directive(''isolateScrolling'', isolateScrolling); function isolateScrolling() { return { restrict: ''A'', link: function(sc, elem, attrs) { $(''.scroll-container'').scrollLock(); } } } })();
And the important piece the plugin fails to document in their website is the HTML structure that it must follow.
<div class="scroll-container locked"> <div class="scrollable" isolate-scrolling> ... whatever ... </div> </div>
The attribute isolate-scrolling
must contain the scrollable
class and it all needs to be inside the scroll-container
class or whatever class you choose and the locked
class must be cascaded.
Check out Leland Kwong''s code.
Basic idea is to bind the wheeling event to the child element, and then use the native javascript property scrollHeight
and the jquery property outerHeight
of the child element to detect the end of the scroll, upon which return false
to the wheeling event to prevent any scrolling.
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;
}
});
Don''t use overflow: hidden;
on body
. It automatically scrolls everything to the top. There''s no need for JavaScript either. Make use of overflow: auto;
:
HTML Structure
<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;
}
Play with the demo here .
I have a similar situation and here''s how i solved it:
All my scrollable elements get the class scrollable .
$(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() makes sure not to scroll parent scrollable area from scrollable child area.
Here''s a vanilla JS implementation of it: http://jsbin.com/lugim/2/edit?js,output
Puedes intentarlo 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'');
});
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();
}
});
The best solution I could find was listening to the scroll event on the window and set the scrollTop to the previous scrollTop if the child div was visible.
prevScrollPos = 0
$(window).scroll (ev) ->
if $(''#mydiv'').is('':visible'')
document.body.scrollTop = prevScrollPos
else
prevScrollPos = document.body.scrollTop
There is a flicker in the background of the child div if you fire a lot of scroll events, so this could be tweaked, but it is hardly noticed and it was sufficient for my use case.
There''s also a funny trick to lock the parent''s scrollTop
when mouse hovers over a scrollable element. This way you don''t have to implement your own wheel scrolling.
Here''s an example for preventing document scroll, but it can be adjusted for any element.
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'');
});