it-swarm.com.de

Bildlauf des übergeordneten Elements verhindern, wenn die Bildlaufposition des inneren Elements nach oben / unten reicht?

Ich habe einen kleinen "schwebenden Werkzeugkasten" - ein Div mit position:fixed; overflow:auto. Funktioniert gut.

Beim Scrollen in diesem Feld (mit dem Mausrad) und Erreichen des unteren Bereichs OR= top übernimmt das übergeordnete Element "" die "Bildlaufanforderung" ": Das Dokument hinter dem Werkzeugkasten wird gescrollt.
- Was nervt und nicht was der User "verlangt".

Ich verwende jQuery und dachte, ich könnte dieses Verhalten mit event.stoppropagation () stoppen:
$("#toolBox").scroll( function(event){ event.stoppropagation() });

Die Funktion wird zwar aufgerufen, die Weitergabe erfolgt jedoch trotzdem (das Dokument scrollt).
- Es ist überraschend schwierig, in SO (und Google)) nach diesem Thema zu suchen, daher muss ich fragen:
Wie kann die Ausbreitung/das Sprudeln des Scroll-Ereignisses verhindert werden?

Bearbeiten:
Arbeitslösung dank amustill (und Brandon Aaron für das Mausrad-Plugin hier:
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();
        }
    }
});
188
T4NK3R

Möglich ist dies mit Brandon Aarons Mousewheel Plugin .

Hier ist eine Demo: http://jsbin.com/jivutakama/edit?html,js,output

37
amustill

Ich füge diese Antwort der Vollständigkeit halber hinzu, weil die akzeptierte Antwort von @amustill das Problem im Internet Explorer nicht richtig löst . Bitte beachten Sie die Kommentare in mein ursprünglicher Beitrag für Details. Darüber hinaus benötigt diese Lösung keine Plugins - nur jQuery.

Im Wesentlichen verarbeitet der Code das Ereignis mousewheel. Jedes dieser Ereignisse enthält ein wheelDelta, das der Anzahl von px entspricht, in die der scrollbare Bereich verschoben werden soll. Wenn dieser Wert >0 ist, scrollen wir up. Wenn wheelDelta<0 ist, scrollen wir down.

FireFox : FireFox verwendet DOMMouseScroll als Ereignis und füllt originalEvent.detail auf, dessen +/- umgekehrt ist oben beschrieben. Im Allgemeinen werden Intervalle von 3 zurückgegeben, während andere Browser einen Bildlauf in Intervallen von 120 zurückgeben (zumindest auf meinem Computer). Zur Korrektur erkennen wir es einfach und multiplizieren es mit -40, um es zu normalisieren.

@amustills Antwort bricht das Ereignis ab, wenn sich der scrollbare Bereich des <div> bereits an der oberen oder unteren Maximalposition befindet. Internet Explorer ignoriert das abgebrochene Ereignis jedoch in Situationen, in denen delta größer als der verbleibende bildlauffähige Bereich ist.

Mit anderen Worten, wenn Sie einen 200px großen <div> haben, der 500px mit scrollbarem Inhalt enthält, und der aktuelle scrollTop400, ein mousewheel Ein Ereignis, das den Browser auffordert, 120px weiter zu scrollen, führt dazu, dass sowohl <div> als auch <body> gescrollt werden, da 400 + 120> 500 .

Also - um das Problem zu lösen, müssen wir etwas anderes tun, wie unten gezeigt:

Der erforderliche jQuery Code lautet:

$(document).on('DOMMouseScroll mousewheel', '.Scrollable', function(ev) {
    var $this = $(this),
        scrollTop = this.scrollTop,
        scrollHeight = this.scrollHeight,
        height = $this.innerHeight(),
        delta = (ev.type == 'DOMMouseScroll' ?
            ev.originalEvent.detail * -40 :
            ev.originalEvent.wheelDelta),
        up = delta > 0;

    var prevent = function() {
        ev.stopPropagation();
        ev.preventDefault();
        ev.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();
    }
});

Im Wesentlichen bricht dieser Code alle Bildlaufereignisse ab, die die unerwünschte Edge-Bedingung hervorrufen würden, und verwendet dann jQuery, um scrollTop von <div> auf den Maximal- oder Minimalwert festzulegen, je nachdem, in welche Richtung mousewheel Event wurde angefordert.

Da das Ereignis in beiden Fällen vollständig abgebrochen wird, wird es niemals an body weitergegeben und löst daher das Problem im IE sowie in allen anderen Browsern.

Ich habe auch ein Arbeitsbeispiel für jsFiddle erstellt.

168
Troy Alford

BEARBEITEN: CodePen-Beispiel

Für AngularJS habe ich folgende Direktive definiert:

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

Und fügte es dann dem scrollbaren Element (dem Dropdown-Menü ul) hinzu:

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

Getestet auf Chrome und Firefox. Das glatte Scrollen von Chrome besiegt diesen Hack, wenn eine große Mausradbewegung nahe (aber nicht) am oberen oder unteren Rand des Bildlaufbereichs ausgeführt wird.

19
dOxxx

Ich weiß, es ist eine ziemlich alte Frage, aber da dies eines der besten Ergebnisse bei Google ist ... musste ich das Scrollen ohne Bubbles ohne jQuery abbrechen und dieser Code funktioniert für mich:

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

Alle Lösungen in diesem Thread erwähnen keine bestehende und native Methode, um dieses Problem zu lösen, ohne DOM neu zu ordnen und/oder Event-Tricks zu verwenden. Es gibt jedoch einen guten Grund: Dieser Weg ist proprietär und nur auf MS-Webplattformen verfügbar. Zitieren von MSDN :

-ms-scroll-chaining - Eigenschaft - Gibt das Bildlaufverhalten an, das auftritt, wenn ein Benutzer während einer Manipulation die Bildlaufgrenze erreicht. Eigenschaftswerte:

chained - Anfangswert. Das nächstgelegene scrollbare übergeordnete Element beginnt zu scrollen, wenn der Benutzer während einer Manipulation ein Scrolllimit erreicht. Es wird kein Bounce-Effekt gezeigt.

none - Ein Bounce-Effekt wird angezeigt, wenn der Benutzer während einer Manipulation ein Bildlauflimit erreicht.

Zugegeben, diese Eigenschaft wird nur von IE10 +/Edge unterstützt. Hier noch ein Erzählendes Zitat :

Um Ihnen ein Gefühl dafür zu vermitteln, wie beliebt das Verhindern von Scroll-Verkettungen ist, entsprechend meiner schnellen http-Archivsuche "-ms-scroll-chaining: none" wird in 0,4% der Top 300K-Seiten verwendet, obwohl in .__ begrenzt ist. Funktionalität und wird nur von IE/Edge unterstützt.

Und nun gute Nachrichten, alle! Ab Chrome 63 haben wir endlich auch ein natives Heilmittel für Blink-basierte Plattformen - und das sind sowohl Chrome (offensichtlich) als auch Android WebView (in Kürze). 

Zitieren der einleitende Artikel :

Die Eigenschaft overscroll-behaviour ist eine neue CSS-Funktion, die .__ steuert. das Verhalten, was passiert, wenn Sie einen Container überschreiben (einschließlich der Seite selbst). Sie können damit die Scroll-Verkettung abbrechen, Deaktivieren/Anpassen der Pull-to-Refresh-Aktion, Deaktivieren des Gummibandes Effekte auf iOS (wenn Safari Overscroll-Verhalten implementiert) und mehr. [...]

Die Eigenschaft nimmt drei mögliche Werte an:

auto - Standardeinstellung. Rollen, die aus dem Element stammen, können sich nach .__ ausbreiten. Ahnenelemente. 

contain - verhindert das Scrollen von Blättern. Schriftrollen nicht an Vorfahren weitergeben, lokale Effekte innerhalb des Knotens werden jedoch angezeigt .. Zum Beispiel der Glättungseffekt bei Overscroll auf Android oder der Rubberbanding-Effekt unter iOS, der den Benutzer benachrichtigt, wenn er eine .__ getroffen hat. Bildlaufgrenze. Hinweis: Mit Overscroll-Verhalten: Enthalten Sie in der HTML-Datei Element verhindert Überscroll-Navigationsaktionen.

none - gleich wie include, verhindert aber auch Overscroll-Effekte innerhalb des Knotens (z. B. Android-Overscroll-Glow oder iOS-Rubberbanding).

[...] Das Beste ist, dass die Verwendung von Overscroll-Verhalten nicht nachteilig ist beeinflussen die Seitenleistung wie die im Intro erwähnten Hacks!

Hier ist diese Funktion in Aktion . Und hier ist das entsprechende CSS-Modul document .

UPDATE: Firefox ist seit Version 59 dem Club beigetreten, und MS Edge wird diese Funktion in Version 18 implementieren. Hier ist die entsprechende caniusage .

11
raina77ow

Es gibt so viele Fragen wie diese mit vielen Antworten, aber ich konnte keine befriedigende Lösung finden, die keine Ereignisse, Skripte, Plugins usw. enthielt. Ich wollte es in HTML und CSS klarstellen. Endlich fand ich eine Lösung, die funktionierte, obwohl der Markup neu strukturiert wurde, um die Ereigniskette zu durchbrechen.


1. Grundproblem

Die Scroll-Eingabe (d. H .: mousewheel), die auf das modale Element angewendet wird, wird in ein Vorfahren-Element übergehen und in derselben Richtung scrollen, wenn ein solches Element scrollbar ist:

(Alle Beispiele sind für Desktop-Auflösungen gedacht.)

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. Kein übergeordneter Bildlauf beim modalen Bildlauf

Der Grund dafür, dass der Vorfahre beim Scrollen endet, ist, dass das Scroll-Ereignis und einige Elemente in der Kette kann damit umgehen. Um dies zu verhindern, können Sie sicherstellen, dass keines der Elemente in der Kette weiß, wie der Bildlauf zu handhaben ist. In unserem Beispiel können wir die Struktur umgestalten, um das Modal aus dem übergeordneten Element zu verschieben. Aus dunklen Gründen reicht es nicht aus, die übergeordneten und die modalen DOM-Geschwister zu behalten. Das übergeordnete Element muss von einem anderen Element eingeschlossen werden, das einen neuen Stapelungskontext erstellt. Ein absolut positionierter Wrapper um das übergeordnete Element kann den Trick ausführen. 

Das Ergebnis ist, dass solange das Modal das Scroll-Ereignis empfängt, das Ereignis nicht zum "Parent" -Element übergeht. 

In der Regel sollte es möglich sein, die DOM-Baumstruktur neu zu entwerfen, um dieses Verhalten zu unterstützen, ohne dass dies Auswirkungen auf die Sicht des Endbenutzers hat.

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 (nur neu):

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

3. Kein Scrollen, außer in Modal, solange es läuft

Die obige Lösung ermöglicht es dem übergeordneten Element weiterhin, Scroll-Ereignisse zu empfangen, solange diese nicht durch das modale Fenster abgefangen werden (d. H., Wenn es durch ein Mausrad ausgelöst wird, während sich der Cursor nicht über dem modalen Fenster befindet). Dies ist manchmal unerwünscht und wir möchten eventuell das Scrollen des Hintergrunds verbieten, während der Modalmodus aktiv ist. Dazu müssen Sie einen zusätzlichen Stapelkontext einfügen, der den gesamten Ansichtsbereich hinter dem Modal umfasst. Wir können dies tun, indem wir ein absolut positioniertes Overlay anzeigen, das bei Bedarf vollständig transparent sein kann (jedoch nicht 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 (neu über # 2):

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

Angular JS-Richtlinie

Ich musste eine Winkelanweisung einwickeln. Das Folgende ist ein Mashup der anderen Antworten hier. getestet auf Chrome und 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;
            }
        }
    }
});

Verwendungszweck

<div prevent-parent-scroll>
    ...
</div>

Hoffentlich hilft dies der nächsten Person, die von einer Google-Suche hierher kommt.

9
Jossef Harush

Als Variante können Sie den folgenden Code verwenden, um Leistungsprobleme bei der Verarbeitung von scroll oder mousewheel zu vermeiden:

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

Arbeitsbeispiel: http://jsbin.com/damuwinarata/4

8
Bohdan Lyzanets

Hier ist eine einfache JavaScript-Version:

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

Verwenden der Scroll-Eigenschaften des nativen Elements mit dem Delta-Wert aus dem Mausrad-Plugin:

$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

Falls noch jemand nach einer Lösung dafür sucht, erledigt das folgende Plugin die Aufgabe http://mohammadyounes.github.io/jquery-scrollLock/

Das Problem der Verriegelung des Mausrads innerhalb eines bestimmten Containers wird vollständig behoben, so dass es nicht zum übergeordneten Element weitergeleitet wird.

Die Scrollgeschwindigkeit des Rads wird nicht geändert. Die Benutzererfahrung wird dadurch nicht beeinträchtigt. und Sie erhalten dasselbe Verhalten unabhängig von der vertikalen Bildlaufgeschwindigkeit des OS-Mausrads (unter Windows kann ein Bildschirm oder eine Zeile mit bis zu 100 Zeilen pro Kerbe eingestellt werden).

Demo: http://mohammadyounes.github.io/jquery-scrollLock/example/

Quelle: https://github.com/MohammadYounes/jquery-scrollLock

6
MK.

die obige Methode ist nicht so natürlich, nach etwas googeln finde ich eine schönere Lösung und keine Notwendigkeit von jQuery. siehe [1] und Demo [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

Das funktioniert eigentlich in AngularJS. Getestet auf Chrome und 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's Antwort als Knockout-Handler:

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

Ich habe eine ähnliche Situation und hier habe ich es gelöst:
Alle meine scrollbaren Elemente erhalten die Klasse 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 () stellt sicher, dass der überrollbare Bildlaufbereich nicht aus dem durchlaufbaren untergeordneten Bereich verschoben wird.

Hier ist eine Vanilla JS-Implementierung: http://jsbin.com/lugim/2/edit?js,output

2
user3259967

Neuer Web-Entwickler hier. Dies funktionierte für mich sowohl bei IE als auch bei Chrome wie ein Zauber.

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

Lassen Sie sich nicht von der Anzahl der Zeilen täuschen, es ist ziemlich einfach - nur ein bisschen ausführlich für die Lesbarkeit (selbstdokumentierender Code ist ftw richtig?)

Ich sollte auch erwähnen, dass die Sprache hier TypeScript ist, aber wie immer ist es einfach, sie in JS zu konvertieren.

2
Vivek Maharajh

Check out Leland Kwong - Code.

Die Grundidee besteht darin, das Wheeling-Ereignis an das untergeordnete Element zu binden und dann die native Javascript-Eigenschaft scrollHeight und die jquery-Eigenschaft outerHeight des untergeordneten Elements zu verwenden, um das Ende der Bildlaufleiste zu erkennen, woraufhin return false zum Rolling-Ereignis gehört, um ein Scrollen zu verhindern.

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

mein jQuery-Plugin:

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

Ich habe dies aus der gewählten Bibliothek gelesen: 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)

Das funktioniert für mich.

1
Drew LeSueur

Für diejenigen, die MooTools verwenden, ist hier der entsprechende Code:

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

Bedenken Sie, dass ich, wie einige andere, einen Wert um ein paar Pixel anpassen musste, dafür ist die Höhe - = 2.

Grundsätzlich besteht der Hauptunterschied darin, dass in MooTools die Delta-Informationen von event.wheel stammen, anstatt von einem zusätzlichen Parameter, der an das Ereignis übergeben wird.

Ich hatte auch Probleme, wenn ich diesen Code an irgendetwas gebunden habe (event.target.scrollHeight für eine gebundene Funktion entspricht nicht diesem.scrollHeight für ein nicht gebundenes).

Hoffe das hilft jemandem so viel wie dieser Beitrag mir geholfen hat;)

1
Clive Galway

jQuery-Plugin mit Emulation des natürlichen Bildlaufs für 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);
                }
            }
        });
    });
};

https://github.com/basselin/jquery-mousewheel-stop-propagation/blob/master/mousewheelStopPropagation.js

0
B.Asselin

Es gibt eine Entscheidung für ES 6 Cross Browser + Mobile Vanilla 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

Verwenden Sie overflow: hidden; nicht für body. Es scrollt automatisch alles nach oben. Es gibt auch keine Notwendigkeit für JavaScript. Verwenden Sie overflow: auto;:

HTML-Struktur

<div class="overlay">
    <div class="overlay-content"></div>
</div>

<div class="background-content">
    lengthy content here
</div>

Styling

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

Spielen Sie mit der Demo hier .

0
Luxiyalu

Es ist erwähnenswert zu erwähnen, dass es bei modernen Frameworks, wie zum Beispiel ReactJS, AngularJS, VueJS usw., einfache Lösungen für dieses Problem gibt, wenn es um feste Positionselemente geht. Beispiele sind Seitenwände oder überlagerte Elemente.

Die Technik wird als "Portal" bezeichnet. Dies bedeutet, dass eine der Komponenten, die in der App verwendet werden, ohne sie tatsächlich aus dem Bereich extrahieren zu müssen, an dem sie verwendet wird, ihre Kinder am unteren Rand des Body-Elements außerhalb des Elements einfügt Sie versuchen, das Scrollen zu vermeiden.

Beachten Sie, dass das Scrollen des Hauptelements selbst nicht vermieden wird. Sie können diese Technik kombinieren und Ihre App in einem scrollenden Div einhängen, um das erwartete Ergebnis zu erzielen.

Beispiel Portalimplementierung in Reacts Material-ui: https://material-ui-next.com/api/portal/

0
Pandaiolo

Es gibt auch einen lustigen Trick, um die scrollTop des Elternteils zu sperren, wenn die Maus über einem scrollbaren Element steht. Auf diese Weise müssen Sie kein eigenes Bildlaufrad verwenden.

Hier ist ein Beispiel zum Verhindern des Blätterns von Dokumenten, es kann jedoch für jedes Element angepasst werden.

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

Ich hasse das Necro-Posting, aber ich habe dies für MooTools gesucht, und dies war das erste, das aufkam ... Das ursprüngliche MooTools-Beispiel würde mit dem Scrollen nach oben funktionieren, aber nicht mit dem Scrollen nach unten, also entschied ich mich, dieses zu schreiben.


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

Verwendungszweck:

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

M.K. bot in seiner Antwort ein tolles Plugin an. Plugin kann nach hier gefunden werden. Der Vollständigkeit halber dachte ich, es wäre eine gute Idee, es in einer Antwort für AngularJS zusammenzustellen.

  1. Beginnen Sie, indem Sie die Laube oder npm spritzen (je nachdem, was bevorzugt wird)

    bower install jquery-scrollLock --save
    npm install jquery-scroll-lock --save
    
  2. Fügen Sie die folgende Direktive hinzu. Ich beschließe, es als Attribut hinzuzufügen

    (function() {
       'use strict';
    
        angular
           .module('app')
           .directive('isolateScrolling', isolateScrolling);
    
           function isolateScrolling() {
               return {
                   restrict: 'A',
                   link: function(sc, elem, attrs) {
                      $('.scroll-container').scrollLock();
                   }
               }
           }
    })();
    
  3. Das wichtigste Element, das das Plugin auf seiner Website nicht dokumentiert, ist die HTML-Struktur, der es folgen muss.

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

Das Attribut isolate-scrolling muss die scrollable-Klasse enthalten, und es muss sich alles innerhalb der scroll-container-Klasse oder der von Ihnen gewählten Klasse befinden, und die locked-Klasse muss kaskadiert sein.

0
LOTUSMS

Die beste Lösung, die ich finden konnte, bestand darin, das Bildlaufereignis im Fenster zu hören und das scrollTop auf das vorherige scrollTop zu setzen, wenn das untergeordnete div sichtbar war.

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

Es gibt ein Flackern im Hintergrund des untergeordneten divs, wenn Sie viele Scroll-Ereignisse auslösen, so dass diese Änderungen vorgenommen werden könnten, aber es wird kaum bemerkt und war für meinen Anwendungsfall ausreichend.

0
GijsjanB