确定用户是点击滚动条还是内容(原生滚动条的onclick事件)

67

我正在尝试使用jQuery创建自定义事件,以便检测当滚动条被单击1时的情况。
虽然有很多文本,但是所有我的问题都是加粗的,而且还有一个JSFiddle示例可以直接操作。

因为我没有找到任何内置的功能来实现这一点,
所以我创建了一个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中都是18像素。
假设没有自定义滚动条,那么某些浏览器中是否有额外的填充或大小?

这些函数看起来都按预期执行(据我所见)。

制作自定义事件有点棘手,但我成功地让它工作了一些。唯一的问题是,如果被点击的元素附加了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供您玩耍。

我正在制作这个项目,是因为我正在开发一个更大的插件。它有一个自定义上下文菜单,显示在我右键单击其中一个滚动条时。我不想要那个。所以我想做一个事件来检查滚动点击(mousedown/up),然后防止上下文菜单被显示出来。但是,为了做到这一点,我需要让滚动点击先于正常点击,并且在可能的情况下,停止正常点击的触发。

我只是在这里公开思考,但也许有一种方法可以获取绑定到元素的所有函数,然后切换它们添加的顺序?我知道函数按它们添加的顺序执行(先添加的先调用),因此,如果我能介入该过程,或许整个将事件注册到JQuery的过程就可以插入到单击事件之前。


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


2
滚动条大小不统一。在 Webkit 中,您可以对其进行相当大的自定义。http://css-tricks.com/examples/WebKitScrollbars/ - mrtsherman
1
请不要更改<select multiple>控件的标准行为。如果它们的行为与用户期望的不同,那么这将非常令人恼火。例如,使用Shift键点击以选择范围,使用Ctrl键点击以选择特定项。有些应用程序会使每次单击项目都切换其状态 - 当然这不是人们所期望的。因此:保持默认行为使用完全自定义的小部件,它看起来不像普通控件,就像在本地应用程序中发生的那样。 - ThiefMaster
2
@ThiefMaster 我已经知道了,但这不应该影响浏览器滚动的默认行为。也许你误解了我的意图?它的目的是添加额外的事件到JQuery中,以便我可以在被点击时让我的其他插件做一些事情。更多功能->更多选项。在我的例子中,我创建了一个自定义上下文菜单,但我不希望在用户右键单击滚动条时弹出上下文菜单(模仿浏览器菜单的相同行为)。为了解决这个问题,我想添加一个事件来防止上下文菜单弹出。 - ShadowScripter
1
@mrtsherman 是的,但它们会在 mousedownmouseup 上触发。我在我的帖子中将它们称为 "click" 事件,并在最底部进行了解释。 - ShadowScripter
1
啊,我明白了。谢谢你为我澄清。+1并收藏。希望能看到答案(我肯定你也是!) - mrtsherman
显示剩余6条评论
12个回答

0

在 Ubuntu 21.10 中经过测试,可以在 Chrome 和 Firefox 上正常工作。

const isScrollClick =
  e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight;

此内容不处理叠加滚动条或从右到左的滚动条。 - Armel Chesnais

-1
clickOnScrollbar = event.clientX > event.target.clientWidth || event.clientY > event.target.clientHeight;

在 Chrome / Mac OS 上进行测试


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接