我有一个小的“浮动工具箱”-一个div的位置:fixed;溢出:汽车。
工作得很好。
但是当滚动到盒子里面(用鼠标滚轮)并到达底部或顶部时,父元素“接管”“滚动请求”:工具箱后面的文档滚动。
-这是恼人的,而不是用户“要求”。
我正在使用jQuery,并认为我可以用event.stoppropagation()停止这种行为:
$(" #工具箱”)。Scroll (function(event){event.stoppropagation()});
它确实进入了函数,但传播仍然发生(文档滚动)
在SO(和谷歌)上搜索这个话题是非常困难的,所以我不得不问:
如何防止滚动事件的传播/冒泡?
编辑:
工作解决方案感谢amustill(和Brandon Aaron的鼠标轮插件在这里:
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();
}
}
});
这在AngularJS中是有效的。
在Chrome和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();
}
});
}
};
})
上面的方法不是那么自然,经过一些谷歌我找到了一个更好的解决方案,不需要jQuery。参见[1]和演示[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/
jQuery插件模拟自然滚动的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
值得一提的是,在像reactJS, AngularJS, VueJS等现代框架中,当处理固定位置元素时,这个问题有简单的解决方案。例如侧板或叠加元素。
这种技术被称为“传送门”,这意味着应用程序中使用的一个组件,不需要从你正在使用它的地方实际提取它,将在body元素的底部装载它的子元素,在你试图避免滚动的父元素之外。
注意,它不会避免滚动body元素本身。你可以结合这种技术,在滚动div中安装你的应用程序,以达到预期的结果。
React material-ui中的门户实现示例:https://material-ui-next.com/api/portal/
使用Brandon Aaron的Mousewheel插件,这是可能的。
这里是一个演示:http://jsbin.com/jivutakama/edit?html,js,output
$(function() {
var toolbox = $('#toolbox'),
height = toolbox.height(),
scrollHeight = toolbox.get(0).scrollHeight;
toolbox.bind('mousewheel', function(e, d) {
if((this.scrollTop === (scrollHeight - height) && d < 0) || (this.scrollTop === 0 && d > 0)) {
e.preventDefault();
}
});
});
作为变量,为了避免滚动或鼠标滚轮处理的性能问题,你可以使用如下代码:
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');
}
});
工作示例:http://jsbin.com/damuwinarata/4