web-dev-qa-db-ja.com

内部要素のスクロール位置が上/下に達したときに親要素がスクロールしないようにしますか?

私は小さな「フローティングツールボックス」を持っています-position:fixed; overflow:autoのあるdivです。うまく動作します。

しかし、そのボックス内を(マウスホイールで)スクロールして下のOR topに達すると、親要素が「スクロールリクエスト」を「引き継ぎます」:ツールボックスの背後にあるドキュメントがスクロールします。
-これは迷惑であり、ユーザーが「求めた」ものではありません。

私はjQueryを使用していますが、event.stoppropagation()でこの動作を停止できると考えました:
$("#toolBox").scroll( function(event){ event.stoppropagation() });

関数に入りますが、それでも伝播は発生します(ドキュメントはスクロールします)
-SO(およびGoogle)でこのトピックを検索するのは驚くほど難しいので、質問する必要があります。
scroll-eventの伝播/バブリングを防ぐ方法

編集:
amustill(およびmousewheel-pluginの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();
        }
    }
});
182
T4NK3R

Brandon Aaronの Mousewheelプラグイン を使用すると可能です。

デモは次のとおりです。 http://jsbin.com/jivutakama/edit?html,js,output

38
amustill

編集: CodePenの例

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;
        });
      }
  };
});

そして、それをスクロール可能な要素に追加しました(ドロップダウンメニューul):

<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>

ChromeおよびFirefoxでテスト済み。 Chromeのスムーズなスクロールは、スクロール領域の上部または下部の近く(ただし、近くではない)でマウスホイールを大きく動かすと、このハックを無効にします。

19
dOxxx

私はそれがかなり古い質問であることを知っていますが、これはGoogleのトップの結果の1つです...

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);
}
19
Nebril

このスレッドで提供されるすべてのソリューションは、DOMを並べ替えたり、イベント防止トリックを使用したりすることなく、この問題を解決する既存のネイティブな方法に言及していません。しかし、正当な理由があります。この方法はプロプライエタリであり、MS Webプラットフォームでのみ利用可能です。引用 MSDN

-ms-scroll-chainingプロパティ-ユーザーがスクロールを押すと発生するスクロール動作を指定します操作中の制限。プロパティ値:

chained-初期値。ユーザーが操作中にスクロール制限に達すると、最も近いスクロール可能な親要素がスクロールを開始します。バウンス効果は表示されません。

none-操作中にユーザーがスクロール制限に達すると、バウンス効果が表示されます。

確かに、このプロパティはIE10 +/Edgeでのみサポートされています。それでも、ここに teling quote があります:

スクロールチェーンの防止がどの程度一般的であるかを理解するために、機能が制限されていて、以下でのみサポートされているにも関わらず、上位30万ページの0.4%で「-ms-scroll-chaining:none」が使用されていますIE/Edge。

そして皆さん、良いニュースです! Chrome 63から始まり、ついにBlinkベースのプラットフォームもネイティブに修復されました。これはChrome(明らかに)とAndroid WebView(間もなく)の両方です。

引用 紹介記事

overscroll-behaviorプロパティは、コンテナ(ページ自体を含む)をオーバースクロールしたときの動作を制御する新しいCSS機能です。スクロールチェーンのキャンセル、プルツーリフレッシュアクションの無効化/カスタマイズ、iOSでのラバーバンディング効果の無効化(Safariがオーバースクロール動作を実装している場合)などに使用できます。[...]

このプロパティは、次の3つの値を取ります。

auto-デフォルト。要素から発生するスクロールは、祖先要素に伝播する場合があります。

contain-スクロールチェーンを防ぎます。スクロールは祖先に伝播しませんが、ノード内のローカル効果が表示されます。たとえば、Androidのオーバースクロールグロー効果や、スクロール境界に達したときにユーザーに通知するiOSのラバーバンディング効果。注:overscroll-behavior:html要素に含むを使用すると、オーバースクロールナビゲーションアクションが防止されます。

none-と同じですが、ノード自体内でのオーバースクロール効果も防ぎます(例:AndroidオーバースクロールグローまたはiOSラバーバンディング)。

[...]最良の部分は、overscroll-behaviorを使用しても、イントロで言及したハッキン​​グのようなページのパフォーマンスに悪影響を与えないことです!

これが feature in action です。そして、対応する CSS Module document です。

UPDATE:Firefoxはバージョン59以降、クラブに参加しており、MS Edgeはバージョン18でこの機能を実装する予定です。対応する caniusage .

11
raina77ow

このような多くの質問があり、多くの答えがありますが、イベント、スクリプト、プラグインなどを含まない満足のいく解決策を見つけることができませんでした。HTMLとCSSでそれをそのまま維持したかったです。イベントチェーンを壊すためにマークアップを再構築する必要がありましたが、最終的には機能するソリューションを見つけました。


1。基本的な問題

モーダル要素に適用されるスクロール入力(つまり、マウスホイール)は、祖先要素に波及し、そのような要素がスクロール可能な場合、同じ方向にスクロールします。

(すべての例はデスクトップの解像度で表示されることを意図しています)

https://jsfiddle.net/ybkbg26c/5/

HTML:

<div id="parent">
  <div id="modal">
    This text is pretty long here.  Hope fully, we will get some scroll bars.
  </div>
</div>

CSS:

#modal {
  position: absolute;
  height: 100px;
  width: 100px;
  top: 20%;
  left: 20%;
  overflow-y: scroll;
}
#parent {
  height: 4000px;
}

2。モーダルスクロールに親スクロールはありません

祖先がスクロールを終了する理由は、スクロールイベントがバブルし、チェーン上の要素がそれを処理できるためです。それを止める方法は、チェーン上のどの要素もスクロールの処理方法を知らないようにすることです。この例では、ツリーをリファクタリングして、モーダルを親要素の外に移動できます。あいまいな理由から、親とモーダルDOM兄弟を保持するだけでは不十分です。親は、新しいスタックコンテキストを確立する別の要素でラップする必要があります。親の周りに絶対に配置されたラッパーがトリックを行うことができます。

モーダルがスクロールイベントを受け取る限り、イベントは「親」要素にバブルしません。

通常、DOMツリーを再設計して、エンドユーザーの表示に影響を与えることなく、この動作をサポートできます。

https://jsfiddle.net/0bqq31Lv/3/

HTML:

<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>

CSS(新規のみ):

#context {
  position: absolute;
  overflow-y: scroll;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

3。モーダル以外の場所でスクロールしない

上記のソリューションでは、モーダルウィンドウによってインターセプトされない限り、親がスクロールイベントを受信できます(つまり、カーソルがモーダル上にないときにマウスホイールによってトリガーされた場合)。これは望ましくない場合があり、モーダルが起動している間はすべてのバックグラウンドスクロールを禁止することができます。そのためには、モーダルの背後にあるビューポート全体に広がる追加のスタッキングコンテキストを挿入する必要があります。これを行うには、絶対配置のオーバーレイを表示します。オーバーレイは、必要に応じて完全に透明にすることができます(ただしvisibility:hiddenは不可)。

https://jsfiddle.net/0bqq31Lv/2/

HTML:

<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>

CSS(#2の上に新しい):

#overlay {
  background-color: transparent;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}
11
Daniel S.

Angular JSディレクティブ

angularディレクティブをラップする必要がありました。以下は、他の回答のマッシュアップです。 ChromeおよびInternet Explorer 11でテスト済み。

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>

これが、Google検索からここに来る次の人に役立つことを願っています。

9
Jossef Harush

これはプレーンなJavaScriptバージョンです。

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);
8
silverwind

バリアントとして、scrollまたはmousewheelの処理に関するパフォーマンスの問題を回避するために、次のようなコードを使用できます。

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

8
Bohdan Lyzanets

Mousewheelプラグインのデルタ値でネイティブ要素のスクロールプロパティを使用する:

$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();
    }
});
7
Pete B

誰かがまだこの解決策を探している場合、次のプラグインが仕事をします http://mohammadyounes.github.io/jquery-scrollLock/

特定のコンテナ内でマウスホイールのスクロールをロックする問題を完全に解決し、親要素への伝播を防ぎます。

ホイールのスクロール速度は変わりませんが、ユーザーエクスペリエンスには影響しません。また、OSマウスホイールの垂直スクロール速度に関係なく同じ動作が得られます(Windowsでは、ノッチごとに1画面または1行から100行まで設定できます)。

デモ: http://mohammadyounes.github.io/jquery-scrollLock/example/

ソース: https://github.com/MohammadYounes/jquery-scrollLock

6
MK.

上記の方法はそれほど自然ではありませんが、いくつかのグーグルの後、私はより良いソリューションを見つけ、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/

4
jinwei

これは実際に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();
                }
            });
        }
    };
})
4
Remot

ノックアウトハンドラーとしての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();
                }
            }
        });
    }
};
4
mhu

私は同様の状況を抱えており、ここに私がそれを解決した方法があります:
スクロール可能な要素はすべて、クラスscrollableを取得します。

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

stopImmediatePropagation()は、スクロール可能な子領域から親のスクロール可能領域をスクロールしないようにします。

次に、Vanilla JSの実装を示します。 http://jsbin.com/lugim/2/edit?js,output

2
user3259967

新しいWeb開発者はこちら。 IEとChromeの両方で、これは私にとって魅力的でした。

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();
        }
    }
}

行の数に惑わされないでください、それは非常に簡単です-読みやすさのためにほんの少し冗長です(自己記録コードは正しいですか?)

また、ここでの言語は TypeScript ですが、いつものように、JSに変換するのは簡単です。

2
Vivek Maharajh

Leland Kwong's コードを確認してください。

基本的な考え方は、ホイールイベントを子要素にバインドし、子要素のネイティブjavascriptプロパティscrollHeightおよびjqueryプロパティouterHeightを使用してスクロールの終わりを検出し、その上でホイールイベントにreturn falseがスクロールを防止することです。

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;
  }
});
1
Vic

私の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;
    });
}
1
psycho brm

私はこれを選択したライブラリから読みました: https://github.com/harvesthq/chosen/blob/master/coffee/chosen.jquery.coffee

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)

これは私のために動作します。

1
Drew LeSueur

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();
            }

私は、他の一部の人と同様に、数ピクセル単位で値を微調整する必要があったことを覚えておいてください。これが高さ-= 2の目的です。

基本的に主な違いは、MooToolsでは、イベントに渡される追加のパラメーターではなく、event.wheelからデルタ情報が取得されることです。

また、このコードを何かにバインドすると問題が発生しました(バインドされた関数のevent.target.scrollHeightは、バインドされていない関数のthis.scrollHeightと等しくありません)

この投稿が私を助けてくれたように、これが誰かの助けになることを願っています;)

1
Clive Galway

internet Explorerの自然なスクロールをエミュレートするjQueryプラグイン

  $.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

0
B.Asselin

ES 6クロスブラウザー+モバイルバニラjsの決定があります。

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)};
}
0
Kaifat Kirsan

bodyoverflow: hidden;を使用しないでください。すべてを自動的に上部にスクロールします。 JavaScriptも必要ありません。 overflow: auto;を使用します。

HTML構造

<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;
}

デモで遊ぶ こちら

0
Lucia

ReactJS、AngularJS、VueJSなどの最新のフレームワークでは、固定位置要素を扱うときにこの問題の簡単な解決策があることに言及する価値があります。例は、サイドパネルまたはオーバーレイ要素です。

この手法は「ポータル」と呼ばれます。つまり、アプリで使用されているコンポーネントの1つは、実際に使用している場所から抽出する必要なく、その子をbody要素の下部、スクロールを避けようとしている親。

Body要素自体のスクロールは避けられないことに注意してください。この手法を組み合わせて、スクロールするdivにアプリをマウントすると、期待どおりの結果が得られます。

Reactのmaterial-uiでのポータル実装の例: https://material-ui-next.com/api/portal/

0
Pandaiolo

マウスがスクロール可能な要素の上にあるときに、親のscrollTopをロックする面白いトリックもあります。この方法では、独自のホイールスクロールを実装する必要はありません。

ドキュメントのスクロールを防止する例を次に示しますが、任意の要素に合わせて調整できます。

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');
});
0
Sebastian Nowak

私はこれをMooToolsで探していましたが、これが最初に登場しました。元のMooToolsの例は上にスクロールしても機能しますが、下にはスクロールしないので、これを書くことにしました。


var stopScroll = function (e) {
    var scrollTo = null;
    if (e.event.type === 'mousewheel') {
        scrollTo = (e.event.wheelDelta * -1);
    } else if (e.event.type === 'DOMMouseScroll') {
        scrollTo = 40 * e.event.detail;
    }
    if (scrollTo) {
        e.preventDefault();
        this.scrollTo(0, scrollTo + this.scrollTop);
    }
    return false;
};

使用法:

(function)($){
    window.addEvent('domready', function(){
        $$('.scrollable').addEvents({
             'mousewheel': stopScroll,
             'DOMMouseScroll': stopScroll
        });
    });
})(document.id);
0
fyrye

M.K。 は彼の答えで素晴らしいプラグインを提供しました。プラグインは here にあります。ただし、完成のために、AngularJSの1つの答えにまとめることをお勧めします。

  1. バウアーまたはnpm(どちらか好ましい方)を注入することから始めます

    bower install jquery-scrollLock --save
    npm install jquery-scroll-lock --save
    
  2. 次のディレクティブを追加します。属性として追加することを選択しています

    (function() {
       'use strict';
    
        angular
           .module('app')
           .directive('isolateScrolling', isolateScrolling);
    
           function isolateScrolling() {
               return {
                   restrict: 'A',
                   link: function(sc, elem, attrs) {
                      $('.scroll-container').scrollLock();
                   }
               }
           }
    })();
    
  3. そして、プラグインがWebサイトに文書化できない重要な部分は、従わなければならないHTML構造です。

    <div class="scroll-container locked">
        <div class="scrollable" isolate-scrolling>
             ... whatever ...
        </div>
    </div>
    

属性isolate-scrollingにはscrollableクラスが含まれている必要があり、すべてscroll-containerクラスまたは選択した任意のクラス内にある必要があり、lockedクラスはカスケード接続する必要があります。

0
LOTUSMS

私が見つけた最良の解決策は、ウィンドウのスクロールイベントをリッスンし、子divが表示されている場合はscrollTopを前のscrollTopに設定することでした。

prevScrollPos = 0
$(window).scroll (ev) ->
    if $('#mydiv').is(':visible')
        document.body.scrollTop = prevScrollPos
    else
        prevScrollPos = document.body.scrollTop

多数のスクロールイベントを発生させると、子divの背景にちらつきが生じるため、これを調整できますが、ほとんど気付かれず、私のユースケースでは十分でした。

0
GijsjanB