Прокручуючи дочірній div, прокручує вікно, як це зупинити?


94

У мене є дів із смугою прокрутки, Коли він досягне кінця, моя сторінка починає прокручуватися. Чи все-таки я можу припинити таку поведінку?


2
@NGLN - не повторне, інше запитання.
sidewinderguy

Відповіді:


68

Ви можете інактивувати прокрутку всієї сторінки, зробивши щось подібне:

<div onmouseover="document.body.style.overflow='hidden';" onmouseout="document.body.style.overflow='auto';"></div>

33
Добре, але змушує панель прокрутки веб-переглядача зникати кожного разу, коли ви наводить курсор на діву.
cstack

@cstack ви маєте рацію, тому краще відповісти на власну відповідь OP (Jeevan).
Імран Буджіо

2
Багато колеса прокрутки браузера зникають і з’являються знову на основі того, що користувач переміщає мишу зараз, тому вищевказаний коментар є проблемою, яка вже не є проблемою.
Кіт Холлідей

Це рішення не працює, якщо сторінка вбудована в рамку iframe.
Гаутам Крішнан

5
не рішення. встановлення переповнення прихованим приховує смугу прокрутки, яка раптово переформатує весь вміст зовнішнього елемента. Крім того, це передбачає, що зовнішній елемент є тілом, але це може бути ще один проділ прокрутки.
robisrob

43

Знайшов рішення.

http://jsbin.com/itajok

Це те, що мені було потрібно.

І це код.

http://jsbin.com/itajok/edit#javascript,html

Використовує плагін jQuery.


Оновлення через повідомлення про припинення використання

Від jquery-mousewheel :

Стара поведінка додавання трьох аргументів ( delta, deltaXі deltaY) до обробника подій тепер застаріла і буде видалена в наступних випусках.

Тоді event.deltaYтепер треба використовувати:

var toolbox = $('#toolbox'),
    height = toolbox.height(),
    scrollHeight = toolbox.get(0).scrollHeight;

toolbox.off("mousewheel").on("mousewheel", function (event) {
  var blockScrolling = this.scrollTop === scrollHeight - height && event.deltaY < 0 || this.scrollTop === 0 && event.deltaY > 0;
  return !blockScrolling;
});

Демо


6
Ваше посилання використовує github для js і брейків, тому що вміст типу бла-бла тут працює: jsbin.com/itajok/207
Michael J. Calkins

Обидва jsbins, схоже, не працюють в емуляторі пристроїв Chrome і в iphone. Хтось знає, чи все-таки це працює?
Дірк Бур,

2
Ваше "рішення" працює лише для подій прокрутки миші, а не клавіш зі стрілками вгору / вниз та зі стрілками.
Скотт

Чому тут потрібен "вимкнено"?
Бред Джонсон

16

Вибране рішення - витвір мистецтва. Думав, це гідно плагіна ....

$.fn.scrollGuard = function() {
    return this
        .on( 'wheel', function ( e ) {
            var event = e.originalEvent;
            var d = event.wheelDelta || -event.detail;
            this.scrollTop += ( d < 0 ? 1 : -1 ) * 30;
            e.preventDefault();
        });
};    

Це стало незручністю для мене, і це рішення настільки чисте порівняно з іншими хаками. Цікаво дізнатися, як більше про те, як це працює і наскільки широко його підтримуватимуть, але вітайте з Джеваном і тим, хто спочатку це придумав. BTW - це потрібно редактору відповідей stackoverflow!

ОНОВЛЕННЯ

Я вважаю, що це краще в тому, що він взагалі не намагається маніпулювати DOM, а лише заважає барботувати умовно ...

$.fn.scrollGuard2 = function() {
  return this
    .on( 'wheel', function ( e ) {
      var $this = $(this);
      if (e.originalEvent.deltaY < 0) {
        /* scrolling up */
        return ($this.scrollTop() > 0);
      } else {
        /* scrolling down */
        return ($this.scrollTop() + $this.innerHeight() < $this[0].scrollHeight);
      }
    })
  ;
};    

Чудово працює в хромі та набагато простіше, ніж інші рішення ... дайте мені знати, як це відбувається в інших місцях ...

ПІДТВОРЕННЯ


3
додавання події DOMMouseScroll змушує його працювати з Firefox → jsfiddle.net/chodorowicz/egqy7mbz/1
chodorowicz

Я здивований, що це не записано в jquery. Я думав, що одним із головних моментів було не доводити до того, який браузер ви використовуєте.
robisrob

насправді схоже, що обидва застаріли ... wheelподія
robisrob

Це призводить до помітно різкого прокручування в Chrome на моєму Macbook. Прийняте рішення не має цієї проблеми.
danvk

невтішно. існує так багато різних версій цього. видається важливим аспектом інтерфейсу, і насправді дивно, що це поведінка за замовчуванням, коли вона така неінтуїтивна. Очевидно, що браузер оснащений тим, що внутрішній діг прокрутки знаходиться на його межі, щоб мати змогу застосувати подію до вікна, то чому б там не було доступних ручок для запиту?
robisrob

8

Ви можете використовувати подію миші на діві, щоб відключити панель прокрутки тіла, а потім подію миші, щоб активувати її знову?

Наприклад, HTML

<div onmouseover="disableBodyScroll();" onmouseout="enableBodyScroll();">
    content
</div>

І тоді javascript так:

var body = document.getElementsByTagName('body')[0];
function disableBodyScroll() {
    body.style.overflowY = 'hidden';
}
function enableBodyScroll() {
    body.style.overflowY = 'auto';
}

12
Можна використовувати і document.bodyзамість цього.
Ry-

8

Ось крос-браузерний спосіб зробити це на осі Y, він працює на настільних ПК та мобільних пристроях. Тестовано на OSX та iOS.

var scrollArea = this.querySelector(".scroll-area");
scrollArea.addEventListener("wheel", function() {
    var scrollTop = this.scrollTop;
    var maxScroll = this.scrollHeight - this.offsetHeight;
    var deltaY = event.deltaY;
    if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
        event.preventDefault();
    }
}, {passive:false});

scrollArea.addEventListener("touchstart", function(event) {
    this.previousClientY = event.touches[0].clientY;
}, {passive:false});

scrollArea.addEventListener("touchmove", function(event) {
    var scrollTop = this.scrollTop;
    var maxScroll = this.scrollHeight - this.offsetHeight;
    var currentClientY = event.touches[0].clientY;
    var deltaY = this.previousClientY - currentClientY;
    if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
        event.preventDefault();
    }
    this.previousClientY = currentClientY;
}, {passive:false});

Це працює приголомшливо! Нічого собі, саме те, що я шукав. На це потрібно безумовно більше грошей.
delato468

Це рішення працює досить добре , але потрібно трохи скорегувати: потреба змінити scrollTop === maxScroll шлях scrollTop >= maxScroll. Здається, це дивно на 1 випадок, це було потрібно
tchiot.ludo

7

Я написав вирішення цього питання

  var div;
  div = document.getElementsByClassName('selector')[0];

  div.addEventListener('mousewheel', function(e) {
    if (div.clientHeight + div.scrollTop + e.deltaY >= div.scrollHeight) {
      e.preventDefault();
      div.scrollTop = div.scrollHeight;
    } else if (div.scrollTop + e.deltaY <= 0) {
      e.preventDefault();
      div.scrollTop = 0;
    }
  }, false);

Одне з небагатьох тут рішень, яке працює без елементів сторінки, що дратівливо стрибає через встановлений прилив.
Скептик

+1 це тверде рішення. якщо ви приєднаєте це до контейнера, який прокручується, ви хочете, щоб в цьому прикладі був div e.currentTarget.
Метт

дуже чистий розчин. Дякую
Thinh Bui

Працював у Chrome 61.0.3163.100 та Safari 11.0, але не у FireFox 56.0 (Mac OS El Capitan)
BigJ

Це найкраще рідне рішення. Однак falseне потрібно вказувати, addEventListenerоскільки це за замовчуванням. Більше того, порівняння повинні бути простими нерівностями ( >і <), а не >=або <=.
Питання Quolonel

6

Якщо я правильно розумію ваше запитання, ви хочете запобігти прокрутці основного вмісту, коли миша знаходиться над div (скажімо, бічна панель). Для цього бічна панель може бути не дочірнім контейнером прокрутки основного вмісту (який був вікном веб-переглядача), щоб запобігти попаданню прокрутки до його батька.

Це, можливо, потребує деяких змін розмітки таким чином:

<div id="wrapper"> 
    <div id="content"> 
    </div> 
</div> 
<div id="sidebar"> 
</div> 

Подивіться, що він працює в цій вибірковій скрипці та порівняйте, що з цією вибірковою скрипкою, яка має дещо іншу поведінку миші на бічній панелі.

Дивіться також прокручування лише одного конкретного ключа з головною панеллю прокрутки браузера .


У цьому випадку бічна панель знаходиться поза дівочої оболонкою. Тож я не думаю, що сувій буде кинутий на батьків
Джеван

Під "цим випадком" ви маєте на увазі свою справу? Якщо ні: ви абсолютно праві. Якщо так: якщо ваша сторінка прокручується в кінці прокрутки Div, то повідомлення прокрутки додається до батьків-діві, тож я думаю, що ваша сторінка та div - це не брати та сестри, а батьки та дитини.
NGLN

Так, Сторінка є батьківщиною мого діва, тож досягнувши кінця, вона починає прокручувати сторінку, чого я не хочу.
Джеван

Якщо ви не можете передати основний вміст свого дивінга, цю проблему неможливо вирішити лише за допомогою HTML + CSS. Це поведінка за замовчуванням.
NGLN

1
Я думаю, що це найбільш ефективне рішення з усіх наданих відповідей; з хорошою чистою розміткою в основі сторінки, набагато менше хаків CSS та JS, щоб отримати бажану поведінку.

6

Як відповів тут , більшість сучасних браузерів зараз підтримують overscroll-behavior: none;властивість CSS, що запобігає ланцюжку прокрутки. І це все, лише один рядок!


2
Це має бути правильною відповіддю у 2020 році. Для мого випадку використання найкращим рішенням було overscroll-behavior: contain;.
Пристань

3

це вимикає прокрутку вікна, якщо ви вводите елемент вибору. працює як принади.

elements = $(".selector");

elements.on('mouseenter', function() {
    window.currentScrollTop = $(window).scrollTop();
    window.currentScrollLeft = $(window).scrollTop();
    $(window).on("scroll.prevent", function() {
        $(window).scrollTop(window.currentScrollTop);
        $(window).scrollLeft(window.currentScrollLeft);
    });
});

elements.on('mouseleave', function() {
    $(window).off("scroll.prevent");
});

Це дійсно робоче рішення. Мені це потрібно було в чистому js, тому я переписав його. Якщо комусь це потрібно, це тут . Для тих, хто все ще шукає рішення, слід ознайомитися з моєю відповіддю нижче .
Андрій Столяр

2

Ви можете інактивувати прокрутку всієї сторінки, зробивши щось подібне, але не відображаючи панель прокрутки!

<div onmouseover="document.body.style.overflow='hidden'; document.body.style.position='fixed';" onmouseout="document.body.style.overflow='auto'; document.body.style.position='relative';"></div>

2
$this.find('.scrollingDiv').on('mousewheel DOMMouseScroll', function (e) {
  var delta = -e.originalEvent.wheelDelta || e.originalEvent.detail;
  var scrollTop = this.scrollTop;
  if((delta < 0 && scrollTop === 0) || (delta > 0 && this.scrollHeight - this.clientHeight - scrollTop === 0)) {
    e.preventDefault();
  }
});

1

На основі відповіді ceed, ось версія, яка дозволяє вкладати захищені елементи прокрутки. Тільки елемент, на якому миша закінчився, прокручується, і він прокручується досить плавно. Ця версія також є повторною. Його можна використовувати кілька разів на одному елементі і правильно видалити та встановити обробники.

jQuery.fn.scrollGuard = function() {
    this
        .addClass('scroll-guarding')
        .off('.scrollGuard').on('mouseenter.scrollGuard', function() {
            var $g = $(this).parent().closest('.scroll-guarding');
            $g = $g.length ? $g : $(window);
            $g[0].myCst = $g.scrollTop();
            $g[0].myCsl = $g.scrollLeft();
            $g.off("scroll.prevent").on("scroll.prevent", function() {
                $g.scrollTop($g[0].myCst);
                $g.scrollLeft($g[0].myCsl);
            });
        })
        .on('mouseleave.scrollGuard', function() {
            var $g = $(this).parent().closest('.scroll-guarding');
            $g = $g.length ? $g : $(window);
            $g.off("scroll.prevent");
        });
};

Одним із простих способів використання є додавання класу, наприклад scroll-guard, до всіх елементів сторінки, на які ви можете прокручувати. Потім використовуйте $('.scroll-guard').scrollGuard()для їх охорони.


0

Якщо ви застосовуєте overflow: hiddenстиль, він повинен піти

редагувати: насправді я неправильно прочитав ваше запитання, це приховає лише смугу прокрутки, але я не думаю, що це те, що ви шукаєте.


1
Мені потрібні обидві смуги прокрутки. Я говорю про свою поведінку. Коли я прокручую, використовуючи трекбол миші, досягаючи кінця прокрутки div, він не повинен прокручувати всю сторінку.
Джеван

0

Я не міг отримати жодної відповіді на роботу в Chrome та Firefox, тому придумав таке об’єднання:

$someElement.on('mousewheel DOMMouseScroll', scrollProtection);

function scrollProtection(event) {
    var $this = $(this);
    event = event.originalEvent;
    var direction = (event.wheelDelta * -1) || (event.detail);
    if (direction < 0) {
        if ($this.scrollTop() <= 0) {
            return false;
        }
    } else {
        if ($this.scrollTop() + $this.innerHeight() >= $this[0].scrollHeight) {
            return false;
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.