确定用户是否单击滚动条或内容(onclick为原生滚动条)

我试图在JQuery中创build自定义事件,应该检测滚动条被点击1
我知道有很多文本,但是我的所有问题都是粗体的,并且有一个JSFiddle示例可以直接使用。

因为我还没有find任何内置的function,
我不得不创build一个hasScroll函数,检查元素是否有滚动条,

 $.fn.hasScroll = function(axis){ var overflow = this.css("overflow"), overflowAxis; if(typeof axis == "undefined" || axis == "y") overflowAxis = this.css("overflow-y"); else overflowAxis = this.css("overflow-x"); var bShouldScroll = this.get(0).scrollHeight > this.innerHeight(); var bAllowedScroll = (overflow == "auto" || overflow == "visible") || (overflowAxis == "auto" || overflowAxis == "visible"); var bOverrideScroll = overflow == "scroll" || overflowAxis == "scroll"; return (bShouldScroll && bAllowedScroll) || bOverrideScroll; }; 

和一个inScrollRange函数,检查点击是否在滚动范围内。

 var scrollSize = 18; function inScrollRange(event){ var x = event.pageX, y = event.pageY, e = $(event.target), hasY = e.hasScroll(), hasX = e.hasScroll("x"), rX = null, rY = null, bInX = false, bInY = false if(hasY){ rY = new RECT(); rY.top = e.offset().top; rY.right = e.offset().left + e.width(); rY.bottom = rY.top +e.height(); rY.left = rY.right - scrollSize; //if(hasX) rY.bottom -= scrollSize; bInY = inRect(rY, x, y); } if(hasX){ rX = new RECT(); rX.bottom = e.offset().top + e.height(); rX.left = e.offset().left; rX.top = rX.bottom - scrollSize; rX.right = rX.left + e.width(); //if(hasY) rX.right -= scrollSize; bInX = inRect(rX, x, y); } return bInX || bInY; } 

所有的滚动条大小是否一致? 例如在Firefox和IE中,它是18px。
假设没有自定义滚动条,在某些浏览器中是否有任何额外的填充或大小?

这些function都按预期执行(从我能看出的)。

制作自定义事件有点棘手,但我有点工作。 唯一的问题是,如果单击的元素附加了一个mousedown / up事件,那么也会触发它。

我似乎无法阻止其他事件触发,同时触发,我所说的,mousedownScroll / mouseupScroll事件。

 $.fn.mousedownScroll = function(fn, data){ if(typeof fn == "undefined" && typeof data == "undefined"){ $(this).trigger("mousedownScroll"); return; } $(this).on("mousedownScroll", data, fn); }; $.fn.mouseupScroll = function(fn, data){ if(typeof fn == "undefined" && typeof data == "undefined"){ $(this).trigger("mouseupScroll"); return; } $(this).on("mouseupScroll", data, fn); }; $(document).on("mousedown", function(e){ if(inScrollRange(e)){ $(e.target).trigger("mousedownScroll"); } }); $(document).on("mouseup", function(e){ if(inScrollRange(e)){ $(e.target).trigger("mouseupScroll"); } }); $("selector").mousedown(function(e){ console.log("Clicked content."); //Fired when clicking scroller as well }); $("selector").mousedownScroll(function(e){ console.log("Clicked scroller."); }); 

如何阻止触发的其他“点击”事件?

当我问,请尽可能优化代码。

这是一个JSFiddle来搞乱。

我做这个的原因是因为我正在开发一个更大的插件。 它有一个自定义的上下文菜单,当我右键单击其中一个滚动条时出现。 我不要那个。 所以我想我应该做一个事件,检查滚动点击(鼠标上/下),然后阻止显示上下文菜单。 为了做到这一点,我需要滚动点击来正常点击之前,并且,如果可能的话,停止正常点击射击。

我只是在这里大声思考,但也许有办法让所有绑定到元素的函数,然后切换它们添加的顺序? 我知道函数是按照它们被添加的顺序执行的(第一次被添加的第一个被调用的),所以,如果我可以进入这个过程,也许整个事件到JQuery的“注册”可能只是在点击事件之前被插入。


1只能使用mousedown / mouseup,因为点击滚动条时点击不会触发。 如果这是错误的,请提供一个工作示例/代码

你可能会使用这个黑客。

您可以尝试劫持mousedownmouseup事件,并在用自定义的function单击滚动条时避开它们。

 $.fn.mousedown = function(data, fn) { if ( fn == null ) { fn = data; data = null; } var o = fn; fn = function(e){ if(!inScrollRange(e)) { return o.apply(this, arguments); } return; }; if ( arguments.length > 0 ) { return this.bind( "mousedown", data, fn ); } return this.trigger( "mousedown" ); }; 

mousedownScrollmouseupScroll事件的逆。

 $.fn.mousedownScroll = function(data, fn) { if ( fn == null ) { fn = data; data = null; } var o = fn; fn = function(e){ if(inScrollRange(e)) { e.type = "mousedownscroll"; return o.apply(this, arguments); } return; }; if ( arguments.length > 0 ) { return this.bind( "mousedown", data, fn ); } return this.trigger( "mousedown" ); }; 

顺便说一句,我认为滚动条宽度是一个操作系统设置。

解决了:

我可以想出最短的滚动条点击检测,在IE,Firefox,Chrome上testing。

 var clickedOnScrollbar = function(mouseX){ if( $(window).outerWidth() <= mouseX ){ return true; } } $(document).mousedown(function(e){ if( clickedOnScrollbar(e.clientX) ){ alert("clicked on scrollbar"); } }); 

工作示例: https : //jsfiddle.net/s6mho19z/

我在以前的项目中遇到同样的问题,我推荐这个解决scheme。 这不是很干净,但它的工作原理,我怀疑我们可以用HTML做得更好。 以下是我的解决scheme的两个步骤:

1.测量桌面环境中滚动条的宽度。

为了实现这一点,在应用程序启动时,执行以下操作:

将以下元素添加到正文中:

<div style='width: 50px; height: 50px; overflow: scroll'><div style='height: 1px;'/></div>

使用jquery的.width()来测量之前添加的元素的内部div,并将滚动条的宽度存储在某处(scollbar的宽度是50 – 内部div的宽度)

删除用于测量滚动条的额外元素(现在您已经得到结果,删除添加到主体中的元素)。

所有这些步骤不应该由用户可见,你有你的操作系统上的滚动条的宽度

例如,你可以使用这个片段:

 var measureScrollBarWidth = function() { var scrollBarMeasure = $('<div />'); $('body').append(scrollBarMeasure); scrollBarMeasure.width(50).height(50) .css({ overflow: 'scroll', visibility: 'hidden', position: 'absolute' }); var scrollBarMeasureContent = $('<div />').height(1); scrollBarMeasure.append(scrollBarMeasureContent); var insideWidth = scrollBarMeasureContent.width(); var outsideWitdh = scrollBarMeasure.width(); scrollBarMeasure.remove(); return outsideWitdh - insideWidth; }; 

2.检查滚动条上是否有点击。

现在你有滚动条的宽度,你可以用事件的坐标计算事件的坐标相对于滚动条的位置矩形和perfom真棒的东西…

如果要过滤点击,可以在处理程序中返回false以防止其传播。

确保您的scollarea的内容完全填满了母公司。

然后,您可以区分点击内容并点击您的容器。

HTML:

 <div class='test container'><div class='test content'></div></div> <div id="results">please click</div> 

CSS:

 #results { position: absolute; top: 110px; left: 10px; } .test { position: absolute; left: 0; top: 0; width: 100px; height: 100px; background-color: green; } .container { overflow: scroll; } .content { background-color: red; } 

JS:

 function log( _l ) { $("#results").html( _l ); } $('.content').on( 'mousedown', function( e ) { log( "content-click" ); e.stopPropagation(); }); $('.container').on( 'mousedown', function( e ) { var pageX = e.pageX; var pageY = e.pageY; log( "scrollbar-click" ); }); 

http://codepen.io/jedierikb/pen/JqaCb

我会提交自己的答案,并接受亚历山大的答案 ,因为它使它完美的工作,并赞成塞缪尔的答案 ,因为它正确计算滚动条的宽度,这也是我所需要的。


这就是说,我决定做两个独立的事件,而不是试图覆盖/重写JQuery的mousedown事件。

这给了我所需要的灵活性,而不需要搞乱JQuery自己的事件,而且很容易做到。

  • mousedownScroll
  • mousedownContent

下面是使用Alexanders和我自己的两个实现。 两者都按照我原本打算的方式工作,但前者可能是最好的。


  • 这是一个实现Alexander答案+ Samuel答案的JSFiddle 。

     $.fn.hasScroll = function(axis){ var overflow = this.css("overflow"), overflowAxis; if(typeof axis == "undefined" || axis == "y") overflowAxis = this.css("overflow-y"); else overflowAxis = this.css("overflow-x"); var bShouldScroll = this.get(0).scrollHeight > this.innerHeight(); var bAllowedScroll = (overflow == "auto" || overflow == "visible") || (overflowAxis == "auto" || overflowAxis == "visible"); var bOverrideScroll = overflow == "scroll" || overflowAxis == "scroll"; return (bShouldScroll && bAllowedScroll) || bOverrideScroll; }; $.fn.mousedown = function(data, fn) { if ( fn == null ) { fn = data; data = null; } var o = fn; fn = function(e){ if(!inScrollRange(e)) { return o.apply(this, arguments); } return; }; if ( arguments.length > 0 ) { return this.bind( "mousedown", data, fn ); } return this.trigger( "mousedown" ); }; $.fn.mouseup = function(data, fn) { if ( fn == null ) { fn = data; data = null; } var o = fn; fn = function(e){ if(!inScrollRange(e)) { return o.apply(this, arguments); } return; }; if ( arguments.length > 0 ) { return this.bind( "mouseup", data, fn ); } return this.trigger( "mouseup" ); }; $.fn.mousedownScroll = function(data, fn) { if ( fn == null ) { fn = data; data = null; } var o = fn; fn = function(e){ if(inScrollRange(e)) { e.type = "mousedownscroll"; return o.apply(this, arguments); } return; }; if ( arguments.length > 0 ) { return this.bind( "mousedown", data, fn ); } return this.trigger( "mousedown" ); }; $.fn.mouseupScroll = function(data, fn) { if ( fn == null ) { fn = data; data = null; } var o = fn; fn = function(e){ if(inScrollRange(e)) { e.type = "mouseupscroll"; return o.apply(this, arguments); } return; }; if ( arguments.length > 0 ) { return this.bind( "mouseup", data, fn ); } return this.trigger( "mouseup" ); }; var RECT = function(){ this.top = 0; this.left = 0; this.bottom = 0; this.right = 0; } function inRect(rect, x, y){ return (y >= rect.top && y <= rect.bottom) && (x >= rect.left && x <= rect.right) } var scrollSize = measureScrollWidth(); function inScrollRange(event){ var x = event.pageX, y = event.pageY, e = $(event.target), hasY = e.hasScroll(), hasX = e.hasScroll("x"), rX = null, rY = null, bInX = false, bInY = false if(hasY){ rY = new RECT(); rY.top = e.offset().top; rY.right = e.offset().left + e.width(); rY.bottom = rY.top +e.height(); rY.left = rY.right - scrollSize; //if(hasX) rY.bottom -= scrollSize; bInY = inRect(rY, x, y); } if(hasX){ rX = new RECT(); rX.bottom = e.offset().top + e.height(); rX.left = e.offset().left; rX.top = rX.bottom - scrollSize; rX.right = rX.left + e.width(); //if(hasY) rX.right -= scrollSize; bInX = inRect(rX, x, y); } return bInX || bInY; } $(document).on("mousedown", function(e){ //Determine if has scrollbar(s) if(inScrollRange(e)){ $(e.target).trigger("mousedownScroll"); } }); $(document).on("mouseup", function(e){ if(inScrollRange(e)){ $(e.target).trigger("mouseupScroll"); } }); }); function measureScrollWidth() { var scrollBarMeasure = $('<div />'); $('body').append(scrollBarMeasure); scrollBarMeasure.width(50).height(50) .css({ overflow: 'scroll', visibility: 'hidden', position: 'absolute' }); var scrollBarMeasureContent = $('<div />').height(1); scrollBarMeasure.append(scrollBarMeasureContent); var insideWidth = scrollBarMeasureContent.width(); var outsideWitdh = scrollBarMeasure.width(); scrollBarMeasure.remove(); return outsideWitdh - insideWidth; }; 
  • 这是我决定做的一个JSFiddle 。

     $.fn.hasScroll = function(axis){ var overflow = this.css("overflow"), overflowAxis, bShouldScroll, bAllowedScroll, bOverrideScroll; if(typeof axis == "undefined" || axis == "y") overflowAxis = this.css("overflow-y"); else overflowAxis = this.css("overflow-x"); bShouldScroll = this.get(0).scrollHeight > this.innerHeight(); bAllowedScroll = (overflow == "auto" || overflow == "visible") || (overflowAxis == "auto" || overflowAxis == "visible"); bOverrideScroll = overflow == "scroll" || overflowAxis == "scroll"; return (bShouldScroll && bAllowedScroll) || bOverrideScroll; }; $.fn.mousedownScroll = function(fn, data){ var ev_mds = function(e){ if(inScrollRange(e)) fn.call(data, e); } $(this).on("mousedown", ev_mds); return ev_mds; }; $.fn.mouseupScroll = function(fn, data){ var ev_mus = function(e){ if(inScrollRange(e)) fn.call(data, e); } $(this).on("mouseup", ev_mus); return ev_mus; }; $.fn.mousedownContent = function(fn, data){ var ev_mdc = function(e){ if(!inScrollRange(e)) fn.call(data, e); } $(this).on("mousedown", ev_mdc); return ev_mdc; }; $.fn.mouseupContent = function(fn, data){ var ev_muc = function(e){ if(!inScrollRange(e)) fn.call(data, e); } $(this).on("mouseup", ev_muc); return ev_muc; }; var RECT = function(){ this.top = 0; this.left = 0; this.bottom = 0; this.right = 0; } function inRect(rect, x, y){ return (y >= rect.top && y <= rect.bottom) && (x >= rect.left && x <= rect.right) } var scrollSize = measureScrollWidth(); function inScrollRange(event){ var x = event.pageX, y = event.pageY, e = $(event.target), hasY = e.hasScroll(), hasX = e.hasScroll("x"), rX = null, rY = null, bInX = false, bInY = false if(hasY){ rY = new RECT(); rY.top = e.offset().top; rY.right = e.offset().left + e.width(); rY.bottom = rY.top +e.height(); rY.left = rY.right - scrollSize; //if(hasX) rY.bottom -= scrollSize; bInY = inRect(rY, x, y); } if(hasX){ rX = new RECT(); rX.bottom = e.offset().top + e.height(); rX.left = e.offset().left; rX.top = rX.bottom - scrollSize; rX.right = rX.left + e.width(); //if(hasY) rX.right -= scrollSize; bInX = inRect(rX, x, y); } return bInX || bInY; } function measureScrollWidth() { var scrollBarMeasure = $('<div />'); $('body').append(scrollBarMeasure); scrollBarMeasure.width(50).height(50) .css({ overflow: 'scroll', visibility: 'hidden', position: 'absolute' }); var scrollBarMeasureContent = $('<div />').height(1); scrollBarMeasure.append(scrollBarMeasureContent); var insideWidth = scrollBarMeasureContent.width(); var outsideWitdh = scrollBarMeasure.width(); scrollBarMeasure.remove(); return outsideWitdh - insideWidth; }; 

应该指出的是,在Mac OSX 10.7+上,没有持久的滚动条。 滚动条出现时,滚动时,消失完成后。 他们也小得多,然后18px(他们是7px)。

屏幕截图: http : //i.stack.imgur.com/zdrUS.png

唯一适用于我的解决scheme(仅针对IE11testing):

 $(document).mousedown(function(e){ bScrollbarClicked = e.clientX > document.documentElement.clientWidth || e.clientY > document.documentElement.clientHeight; 

});

我需要在mousedown上检测滚动条,但不是在窗口上,而是在div上,而且我有元素来填充内容,我用它来检测没有滚动条的大小:

 .element { position: relative; } .element .fill-node { position: absolute; left: 0; top: -100%; width: 100%; height: 100%; margin: 1px 0 0; border: none; opacity: 0; pointer-events: none; box-sizing: border-box; } 

检测代码类似于@DariuszSikorski答案,但包括偏移和使用内部滚动的节点:

 function scrollbar_event(e, node) { var left = node.offset().left; return node.outerWidth() <= e.clientX - left; } var node = self.find('.fill-node'); self.on('mousedown', function(e) { if (!scrollbar_event(e, node)) { // click on content } }); 

我还没有尝试,我知道这将是一个很长的路要走,但是你可以用javascript,html和css创build你自己的滚动条,当你点击你的div(或者滚动条)的时候,你会知道这个。 在这里你可以看到如何用CSS创build一个滚动条: http : //www.apptools.com/examples/scroller.php