59

スクロールバーがクリックされたときに検出することになっているカスタムイベントを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では18pxです。
カスタマイズされたスクロールバーがないと仮定すると、一部のブラウザに余分なパディングやサイズはありますか?

これらの機能はすべて意図したとおりに機能します(私が認識できることから)。

カスタムイベントの作成は少しトリッキーでしたが、ある程度機能するようになりました。唯一の問題は、クリックされた要素に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です。

私がこれを作っている理由は、私が開発しているより大きなプラグインのためです。スクローラーの1つを右クリックすると表示されるカスタムコンテキストメニューがあります。私はそれを望んでいません。そこで、スクロールクリック(マウスアップ/ダウン)をチェックするイベントを作成して、コンテキストメニューが表示されないようにする必要があると思いました。ただし、これを行うには、スクロールクリックを通常のクリックの前に配置し、可能であれば通常のクリックの発生を停止する必要があります。

ここで大声で考えているだけですが、要素にバインドされているすべての関数を取得して、それらが追加された順序を切り替える方法があるのではないでしょうか。関数は追加された順序(最初に追加された最初の呼び出し)で実行されることを知っているので、そのプロセスを利用できれば、JQueryへのイベントの「登録」全体をクリックイベントの前に挿入できます。


1は、スクロールバーをクリックしてもクリックがトリガーされないため、mousedown/mouseupのみを使用できます。これが誤りの場合は、実用的な例/コードを提供してください

4

12 に答える 12

28

解決済み:

IE、Firefox、Chromeでテストされた、私が思いついた最短のスクロールバークリック検出。

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/

于 2015-11-19T09:00:05.423 に答える
18

あなたはおそらくこのハックを使うかもしれません。

mousedownカスタムパワード関数でスクロールバーをクリックすると、イベントとmouseupイベントをハイジャックして回避することができます。

$.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" );
};

mousedownScrollそして、mouseupScrollイベントの逆。

$.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" );
};

ちなみに、スクロールバーの幅はOSの設定だと思います。

于 2012-04-07T12:14:24.160 に答える
17

次のソリューションを使用して、ユーザーが要素のスクロールバー上でマウスをクリックしたかどうかを検出します。ウィンドウのスクロールバーでどのように機能するかをテストしませんでした。ピートのソリューションは、ウィンドウスクロールの方がうまくいくと思います。

window.addEventListener("mousedown", onMouseDown);

function onMouseDown(e) {
  if (e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight) 
  {
      // mouse down over scroll element
   }
}
于 2018-01-03T11:37:33.283 に答える
8

以前のプロジェクトでも同じ問題が発生したので、この解決策をお勧めします。あまりきれいではありませんが、機能します。htmlを使用するともっとうまくいくとは思えません。これが私のソリューションの2つのステップです。

1.デスクトップ環境でスクロールバーの幅を測定します。

これを実現するには、アプリケーションの起動時に次のことを実行します。

次の要素を本文に追加します。

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

jQUeryの.width()を使用して、以前に追加した要素の内部divのwithを測定し、スクロールバーの幅をどこかに格納します(scollbarの幅は50です-内部divのwith)

スクロールバーの測定に使用した余分な要素を削除します(結果が得られたので、本体に追加した要素を削除します)。

これらの手順はすべてユーザーに表示されるべきではなく、OSのスクロールバーの幅があります

たとえば、次のスニペットを使用できます。

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.スクロールバーをクリックしているかどうかを確認します。

スクロールバーの幅がわかったので、イベントの座標を使用して、スクロールバーの位置の長方形を基準にしたイベントの座標を計算し、すばらしいことを実行できます...

クリックをフィルタリングする場合は、ハンドラーでfalseを返し、クリックの伝播を防ぐことができます。

于 2012-05-23T16:13:15.730 に答える
8

scollareaのコンテンツが親divを完全に[過剰]満たすようにします。

次に、コンテンツのクリックとコンテナのクリックを区別できます。

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

于 2014-06-23T15:01:50.017 に答える
3

ここには、、などを含む多くの答えがありますevent.clientXelement.clientHeightそれらはすべて間違っています。それらを使用しないでください。

  • overflow: scroll上で説明したように、スクロールバーがオーバーレイとして表示されるプラットフォームがあります。または、を使用して強制した可能性がありますoverflow: overlay
  • Macは、マウスを抜き差しすることで、スクロールバーを永続とオーバーレイの間で切り替えることができます。これは、「起動時の対策」手法を打ち破ります。
  • 垂直スクロールバーが左側に表示され、右から左への読み取り順序が表示されます。これは、RTLを一貫してテストしていない可能性があるため、右から左への読み取り順序に関する特別なロジックがたくさんない限り、クライアント幅の比較に失敗します。

あなたは見る必要がありますevent.target。必要に応じて、スクロール要素のクライアント領域のすべてを占める内部要素を使用し、その要素またはその子孫であるかどうかを確認します。 event.target

于 2020-04-26T15:44:29.337 に答える
0

Mac OSX 10.7以降では、永続的なスクロールバーがないことに注意してください。スクロールするとスクロールバーが表示され、終了するとスクロールバーが消えます。また、18pxよりはるかに小さいです(7pxです)。

スクリーンショット:http: //i.stack.imgur.com/zdrUS.png

于 2012-05-08T17:15:02.853 に答える
0

私は自分の答えを提出し、Alexanderの答えを受け入れます。これは完全に機能するためです。また、Samuelの答えは、スクロールバーの幅を正しく計算するため、私も必要としていたので、賛成します。


そうは言っても、JQueryのイベントを上書き/上書きするのではなく、2つの独立したイベントを作成することにしmousedownました。

これにより、JQuery自体のイベントをいじることなく、必要な柔軟性が得られ、非常に簡単に実行できました。

  • mousedownScroll
  • mousedownContent

以下は、Alexandersを使用した2つの実装と私自身の実装です。どちらも当初の意図どおりに機能しますが、おそらく前者が最適です。


  • これは、アレクサンダーの答えとサミュエルの答えを実装する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;
    };
    
于 2013-03-15T12:18:17.807 に答える
0

私のために働く唯一の解決策(IE11に対してのみテストされています):

$(document).mousedown(function(e){
    bScrollbarClicked = e.clientX > document.documentElement.clientWidth || e.clientY > document.documentElement.clientHeight;
});
于 2016-09-08T21:00:59.820 に答える
0

マウスダウンでスクロールバーを検出する必要がありましたが、ウィンドウではなく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
   }
});
于 2017-11-08T17:06:29.103 に答える
0

ubuntu21.10のchromeとfirefoxでテストおよび動作しています。

const isScrollClick =
  e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight;
于 2022-02-24T13:04:25.263 に答える
-1
clickOnScrollbar = event.clientX > event.target.clientWidth || event.clientY > event.target.clientHeight;

Chrome /MacOSでテスト済み

于 2019-10-15T13:46:40.997 に答える