Javascript 当内部元素滚动位置达到顶部/底部时,是否防止父元素滚动?
我有一个小“浮动工具箱”-一个div,其Javascript 当内部元素滚动位置达到顶部/底部时,是否防止父元素滚动?,javascript,jquery,scroll,event-bubbling,event-propagation,Javascript,Jquery,Scroll,Event Bubbling,Event Propagation,我有一个小“浮动工具箱”-一个div,其位置:fixed;溢出:自动。 很好用 但当在该框内滚动(使用鼠标滚轮)并到达底部或顶部时,父元素“接管”了“滚动请求”:工具箱后面的文档滚动。 -这很烦人,不是用户“要求的” 我正在使用jQuery,并认为可以使用event.stoppropagation()停止这种行为: $(“#工具箱”).scroll(函数(事件){event.stoppropagation()}) 它确实进入了函数,但仍然会进行传播(文档滚动) -在SO(和谷歌)上搜索这个主题非
位置:fixed;溢出:自动
。
很好用
但当在该框内滚动(使用鼠标滚轮)并到达底部或顶部时,父元素“接管”了“滚动请求”:工具箱后面的文档滚动。-这很烦人,不是用户“要求的” 我正在使用jQuery,并认为可以使用event.stoppropagation()停止这种行为:
$(“#工具箱”).scroll(函数(事件){event.stoppropagation()})代码>
它确实进入了函数,但仍然会进行传播(文档滚动)
-在SO(和谷歌)上搜索这个主题非常困难,所以我不得不问:
如何防止滚动事件的传播/冒泡
编辑:
工作解决方案感谢Amustil(以及Brandon Aaron在此处提供鼠标轮插件:
$(“.ToolPage”).bind('mouseweel',函数(e,d)
var t=$(本);
如果(d>0&&t.scrollTop()==0){
e、 预防默认值();
}
否则{
if(d<0&(t.scrollTop()==t.get(0.scrollHeight-t.innerHeight()){
e、 预防默认值();
}
}
});
使用布兰登·艾伦的产品是可能的
这里是一个演示:对于那些使用MooTools的人,这里是等效代码:
'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();
}
“鼠标滚轮”:函数(事件){
var height=this.getSize().y;
高度-=2;//不知道我为什么需要这个小家伙
if((this.scrollTop==(this.scrollHeight-height)&&event.wheel<0)|
(this.scrollTop==0&&event.wheel>0)){
event.preventDefault();
}
请记住,我和其他一些人一样,必须将一个值调整几px,这就是高度-=2的含义
基本上,主要区别在于,在MooTools中,增量信息来自event.wheel,而不是传递给事件的额外参数
此外,如果将此代码绑定到任何对象,我也会遇到问题(绑定函数的event.target.scrollHeight不等于非绑定函数的this.scrollHeight)
希望这篇文章能像这篇文章帮助我一样帮助别人;)我知道这是一个很老的问题,但因为这是谷歌的顶级结果之一……我不得不在没有jQuery的情况下取消滚动冒泡,这段代码对我很有用:
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);
}
您可以这样尝试:
$('#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');
});
我的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;
});
}
$('.child').dontscrollpent();
$.fn.dontScrollParent=函数()
{
this.bind('mousewheel-DOMMouseScroll',函数(e)
{
var delta=e.originalEvent.wheelDelta | | |-e.originalEvent.detail;
如果(增量>0&&$(this.scrollTop()=this.scrollHeight-$(this.height())
返回false;
返回true;
});
}
amustill作为击倒处理程序的回答:
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();
}
}
});
}
};
ko.bindingHandlers.preventParentScroll={
init:function(元素、valueAccessor、allBindingsAccessor、上下文){
$(元素).鼠标滚轮(功能(e,d){
var t=$(本);
如果(d>0&&t.scrollTop()==0){
e、 预防默认值();
}
否则{
if(d<0&(t.scrollTop()==t.get(0.scrollHeight-t.innerHeight()){
e、 预防默认值();
}
}
});
}
};
我在MooTools中搜索这个,这是第一个出现的。
最初的MooTools示例可以向上滚动,但不能向下滚动,因此我决定编写这个示例
- MooTools 1.4.5:
- MooTools 1.3.2:
- MooTools 1.2.6:
用法:
(function)($){
window.addEvent('domready', function(){
$$('.scrollable').addEvents({
'mousewheel': stopScroll,
'DOMMouseScroll': stopScroll
});
});
})(document.id);
我添加此答案是为了完整性,因为@amustill接受的答案不能正确解决Internet Explorer中的问题。有关详细信息,请参阅中的注释。此外,此解决方案不需要任何插件-仅jQuery
本质上,代码通过处理mouseweel
事件来工作。每个这样的事件都包含一个wheelDelta
,该值等于它要将可滚动区域移动到的px
。如果该值为>0
,则我们将向上滚动。如果wheeldeldelta
使用本机ele使用鼠标滚轮插件中的增量值编辑滚动属性:
$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();
}
});
$elem.on('mouseweel',函数(e,delta){
//将鼠标滚动限制在此元素的滚动范围内。
如果(
此.scrollTop<1&&delta>0||
(this.clientHeight+this.scrollTop)==this.scrollHeight&&delta<0
) {
e、 预防默认值();
}
});
编辑:
对于AngularJS,我定义了以下指令:
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;
});
}
};
});
module.directive('isolateScrolling',function(){
返回{
限制:“A”,
链接:功能(范围、元素、属性){
元素绑定('DOMMouseScroll',函数(e){
如果(e.detail>0&&this.clientHeight+this.scrollTop==this.scrollHeight){
this.scrollTop=this.scrollHeight-this.clientHeight;
e、 停止传播();
e、 预防默认值();
返回false;
}
else if(e.detail<0&&this.scrollTop 0&&this.clientHeight+this.scrollTop>=this.scrollHeight){
this.scrollTop=this.scrollHeight-this.clientHeight;
e、 停止传播();
e、 预防默认值();
返回false;
}
else if(e.deltaY<0&&this.scrollTopjQuery插件,带有针对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);
}
}
});
});
};
$.fn.mouseweelStoppRopagation=函数(选项){
选项=$。扩展({
//默认值
wheelstop:null//函数
},选项);
//相容性
var isMsIE=('MicrosoftInternetExplorer'==navigator.appName);
var docElt=docume
$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();
}
});
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;
});
}
};
});
<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>
$.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);
}
}
});
});
};
prevScrollPos = 0
$(window).scroll (ev) ->
if $('#mydiv').is(':visible')
document.body.scrollTop = prevScrollPos
else
prevScrollPos = document.body.scrollTop
$(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();
}
});
body.noscroll {
overflow: hidden;
}
.scrollable {
max-height: 200px;
overflow-y: scroll;
border: 1px solid #ccc;
}
<div class="scrollable">
...A bunch of items to make the div scroll...
</div>
...A bunch of text to make the body scroll...
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');
}
});
<div class="overlay">
<div class="overlay-content"></div>
</div>
<div class="background-content">
lengthy content here
</div>
.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;
}
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();
}
}
}
.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();
}
});
}
};
})
$('.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();
}
});
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;
}
});
<div id="parent">
<div id="modal">
This text is pretty long here. Hope fully, we will get some scroll bars.
</div>
</div>
#modal {
position: absolute;
height: 100px;
width: 100px;
top: 20%;
left: 20%;
overflow-y: scroll;
}
#parent {
height: 4000px;
}
<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>
#context {
position: absolute;
overflow-y: scroll;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
<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>
#overlay {
background-color: transparent;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
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');
});
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);
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;
}
}
}
});
<div prevent-parent-scroll>
...
</div>
bower install jquery-scrollLock --save
npm install jquery-scroll-lock --save
(function() {
'use strict';
angular
.module('app')
.directive('isolateScrolling', isolateScrolling);
function isolateScrolling() {
return {
restrict: 'A',
link: function(sc, elem, attrs) {
$('.scroll-container').scrollLock();
}
}
}
})();
<div class="scroll-container locked">
<div class="scrollable" isolate-scrolling>
... whatever ...
</div>
</div>
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)
function stopParentScroll(selector) {
let last_touch;
let MouseWheelHandler = (e, selector) => {
let delta;
if(e.deltaY)
delta = e.deltaY;
else if(e.wheelDelta)
delta = e.wheelDelta;
else if(e.changedTouches){
if(!last_touch){
last_touch = e.changedTouches[0].clientY;
}
else{
if(e.changedTouches[0].clientY > last_touch){
delta = -1;
}
else{
delta = 1;
}
}
}
let prevent = function() {
e.stopPropagation();
e.preventDefault();
e.returnValue = false;
return false;
};
if(selector.scrollTop === 0 && delta < 0){
return prevent();
}
else if(selector.scrollTop === (selector.scrollHeight - selector.clientHeight) && delta > 0){
return prevent();
}
};
selector.onwheel = e => {MouseWheelHandler(e, selector)};
selector.onmousewheel = e => {MouseWheelHandler(e, selector)};
selector.ontouchmove = e => {MouseWheelHandler(e, selector)};
}