предотвратить пузыри скролл от элемента к окну - PullRequest
54 голосов
/ 22 сентября 2009

У меня есть окно модального окна (всплывающее окно), которое содержит iframe,
и внутри этого iframe есть div , который можно прокручивать.

Когда я прокручиваю внутренний DIV iframe, и он достигает своего верхнего или нижнего предела,
окно самого браузера начинает прокручиваться. это нежелательное поведение .

Я пробовал что-то вроде этого, что убивает прокрутку главного окна, когда
onMouseEnter, когда мышь входит в область всплывающего окна:

e.preventDefault () не работает должным образом по некоторым причинам ...

$("#popup").mouseenter(function(){
   $(window).bind("scroll", function(e){
        e.preventDefault();
   }); 
}).mouseleave(function(){
    $(window).unbind("scroll");
});

Обновление

Похоже, что сейчас в 2013 году e.preventDefault(); достаточно ...

Ответы [ 14 ]

26 голосов
/ 22 сентября 2009

Извините, насколько я знаю, невозможно отменить какое-либо событие прокрутки.

Обе W3 и MSDN говорят:

Cancelable  No
Bubbles     No

Я думаю, вам придется оставить это на усмотрение авторов браузера. Firefox (3.5 в Linux, в любом случае), кажется, ведет себя лучше: он прокручивает родительский элемент, только если дочерний элемент уже находится в верхнем / нижнем конце в тот момент, когда вы начинаете , используя колесо прокрутки. *

17 голосов
/ 04 января 2011

Если мы не можем предотвратить прокрутку окна, почему бы не отменить это? То есть, перехватывая событие прокрутки, а затем прокручивая обратно в фиксированное положение.

Следующий код блокирует ось Y, пока один находится над $("#popup"):

// here we store the window scroll position to lock; -1 means unlocked
var forceWindowScrollY = -1;

$(window).scroll(function(event) {
  if(forceWindowScrollY != -1 && window.scrollY != forceWindowScrollY) {
    $(window).scrollTop(forceWindowScrollY);    
  }
});

$("#popup").hover(function() {
  if(forceWindowScrollY == -1) {
    forceWindowScrollY = $(window).scrollTop();
  }
}, function() {
  forceWindowScrollY = -1;
});

Я использую это для поля подсказки запроса на http://bundestube.de/ (введите несколько символов в верхнее окно поиска, чтобы сделать прокручиваемую панель видимой):

Screenshot

Это работает безупречно в Chrome / Safari (Webkit) и с некоторыми скроллами в Firefox и Opera. По некоторым причинам это не работает с моей установкой IE. Я предполагаю, что это связано с методом наведения jQuery, который, кажется, не работает правильно в 100% всех случаев.

4 голосов
/ 15 января 2019

Решено (для современных браузеров) с использованием простого свойства CSS:
overscroll-поведения

body{
  height: 600px;
  overflow: auto;
}

section{
  width: 50%;
  height: 50%;
  overflow: auto;
  background: lightblue;
  overscroll-behavior: none; /*   <--- the trick    */
}

section::before{
  content: '';
  height: 200%;
  display: block;
}
<section>
 <input value='end' />
</section>

Просто примените это свойство стиля к элементу, к которому свиток должен быть "заблокирован", и событие прокрутки не будет всплывать ни к какому родительскому элементу, который также может иметь прокрутку.


То же, что и выше, но без хитрость:

body{
  height: 600px;
  overflow: auto;
}

section{
  width: 50%;
  height: 50%;
  overflow: auto;
  background: lightblue;
}

section::before{
  content: '';
  height: 200%;
  display: block;
}
<section>
 <input value='end' />
</section>
3 голосов
/ 14 сентября 2012

мой плагин 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;
    });
}
3 голосов
/ 20 марта 2012

Я знаю, что это довольно старый вопрос, но так как это один из лучших результатов в Google ... Мне пришлось как-то отменить всплывающее окно с прокруткой без jQuery, и этот код работает для меня:

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);
}
1 голос
/ 07 октября 2016

Вот как я решил проблему:

Я вызываю следующее, когда открываю всплывающее окно:

$('body').css('overflow','hidden');

Затем, когда я закрываю всплывающее окно, я называю это:

$('body').css('overflow','auto');

Всплывающее окно должно быть модальным, поэтому взаимодействие с основным телом не требуется

Работает довольно хорошо

0 голосов
/ 25 апреля 2018

На данный момент в 2018 году и далее достаточно e.preventDefault.

$('.elementClass').on("scroll", function(e){
    e.preventDefault();
 }); 

Это предотвратит прокрутку к родителю.

0 голосов
/ 23 июня 2016
$('.scrollable').on('DOMMouseScroll mousewheel', function (e) {
    var up = false;
    if (e.originalEvent) {
        if (e.originalEvent.wheelDelta) up = e.originalEvent.wheelDelta / -1 < 0;
        if (e.originalEvent.deltaY) up = e.originalEvent.deltaY < 0;
        if (e.originalEvent.detail) up = e.originalEvent.detail < 0;
    }

    var prevent = function () {
        e.stopPropagation();
        e.preventDefault();
        e.returnValue = false;
        return false;
    }

    if (!up && this.scrollHeight <= $(this).innerHeight() + this.scrollTop + 1) {
        return prevent();
    } else if (up && 0 >= this.scrollTop - 1) {
        return prevent();
    }
});
0 голосов
/ 15 июня 2016

Я хотел бы добавить немного обновленный код, который, по моему мнению, работает лучше всего:

var yourElement = $('.my-element');

yourElement.on('scroll mousewheel wheel 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).outerHeight())
        return false;

    return true;
});

Разница между этим и тем, что уже упоминалась выше, заключается в добавлении большего количества событий и использовании outerHeight () вместо height () , чтобы избежать сбоя, если элемент имеет прокладку!

0 голосов
/ 20 марта 2015

Новый веб-разработчик здесь. Это сработало для меня как в 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();
        }
    }
}

Не позволяйте количеству строк ввести вас в заблуждение, это довольно просто - просто немного многословно для читабельности (самодокументированный код, верно?)

...