Menggulir div anak akan menggulung jendela, bagaimana cara menghentikannya?

Jawaban:

68

Anda dapat menonaktifkan pengguliran seluruh halaman dengan melakukan sesuatu seperti ini:

<div onmouseover="document.body.style.overflow='hidden';" onmouseout="document.body.style.overflow='auto';"></div>
Teemu
sumber
33
Bagus, tetapi itu membuat bilah gulir browser menghilang setiap kali Anda mengarahkan kursor ke div.
cstack
@cstack kamu benar itu sebabnya jawaban OP (Jeevan) sendiri lebih baik.
Imran Bughio
2
Banyak roda gulir browser menghilang dan muncul kembali berdasarkan pengguna menggerakkan mouse sekarang, jadi masalah komentar di atas tidak lagi menjadi masalah.
Keith Holliday
Solusi ini tidak berfungsi saat halaman disematkan dalam iframe.
Gautam Krishnan
5
bukan solusi. mengatur luapan menjadi tersembunyi menyembunyikan bilah gulir yang tiba-tiba memformat ulang semua konten elemen luar. juga, ini mengasumsikan elemen luar adalah tubuh tetapi bisa jadi div bergulir lainnya.
robisrob
43

Menemukan solusinya.

http://jsbin.com/itajok

Inilah yang saya butuhkan.

Dan inilah kodenya.

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

Menggunakan Plug-in jQuery.


Pembaruan karena pemberitahuan penghentian

Dari jquery-mousewheel :

Perilaku lama menambahkan tiga argumen ( delta,, deltaXdan deltaY) ke event handler sekarang tidak digunakan lagi dan akan dihapus di rilis selanjutnya.

Lalu, event.deltaYsekarang harus digunakan:

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

Demo

Jeevan
sumber
6
Tautan Anda menggunakan github untuk js dan break karena tipe konten blah blah di sini yang ini berfungsi: jsbin.com/itajok/207
Michael J. Calkins
Kedua jsbins tampaknya tidak berfungsi di emulator perangkat Chrome dan iPhone. Adakah yang tahu apakah ini masih berfungsi?
Dirk Boer
2
"Solusi" Anda hanya berfungsi untuk acara gulir mouse, bukan tombol panah atas / bawah atau tombol panah.
Scott
Mengapa "off" diperlukan di sini?
Brad Johnson
16

Solusi yang dipilih adalah karya seni. Pikir itu layak untuk sebuah plugin ....

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

Ini merupakan ketidaknyamanan yang berkelanjutan bagi saya dan solusi ini sangat bersih dibandingkan dengan peretasan lain yang pernah saya lihat. Penasaran untuk mengetahui lebih banyak tentang cara kerjanya dan seberapa luas dukungannya, tetapi bersoraklah untuk Jeevan dan siapa pun yang awalnya muncul dengan ini. BTW - editor jawaban stackoverflow membutuhkan ini!

MEMPERBARUI

Saya percaya ini lebih baik karena tidak mencoba memanipulasi DOM sama sekali, hanya mencegah gelembung bersyarat ...

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

Berfungsi hebat di krom dan jauh lebih sederhana daripada solusi lain ... beri tahu saya bagaimana tarifnya di tempat lain ...

BIOLA

robisrob
sumber
3
menambahkan acara DOMMouseScroll membuatnya bekerja dengan Firefox → jsfiddle.net/chodorowicz/egqy7mbz/1
chodorowicz
Saya terkejut ini tidak ditulis ke dalam jquery. Saya pikir salah satu poin utamanya adalah tidak harus peduli browser apa yang Anda gunakan.
robisrob
sebenarnya sepertinya keduanya sudah usang ... wheelevent
robisrob
Ini menghasilkan pengguliran yang terasa tersentak-sentak di Chrome di Macbook saya. Solusi yang diterima tidak memiliki masalah ini.
danvk
mengecewakan. Ada begitu banyak versi berbeda dari ini. sepertinya merupakan aspek penting dari ui, dan sungguh mengejutkan bahwa ini adalah perilaku default ketika tidak intuitif. Jelas browser diperlengkapi untuk mengetahui div gulir dalam berada pada batasnya untuk dapat menerapkan acara ke jendela sebagai gantinya, jadi mengapa tidak ada pegangan yang tersedia untuk menanyakannya?
robisrob
8

Anda dapat menggunakan peristiwa gerakan mouse pada div untuk menonaktifkan bilah gulir tubuh dan kemudian peristiwa mouseout untuk mengaktifkannya lagi?

Misalnya HTML

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

Dan kemudian javascript seperti ini:

var body = document.getElementsByTagName('body')[0];
function disableBodyScroll() {
    body.style.overflowY = 'hidden';
}
function enableBodyScroll() {
    body.style.overflowY = 'auto';
}
joe92
sumber
12
Anda juga bisa menggunakannya document.body.
Ry-
8

Berikut cara lintas-browser untuk melakukan ini pada sumbu Y, ini berfungsi di desktop dan seluler. Diuji di OSX dan 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});
Patrick Matte
sumber
Ini bekerja luar biasa! Wow, persis seperti yang saya cari. Itu pasti membutuhkan lebih banyak suara positif.
delato468
Solusi ini bekerja dengan cukup baik tetapi perlu sedikit sebuah menyesuaikan: kebutuhan untuk mengubah scrollTop === maxScroll oleh scrollTop >= maxScroll. Tampaknya aneh dengan 1 kasus, itu dibutuhkan
tchiot.ludo
7

Saya menulis penyelesaian untuk masalah ini

  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);
Alex Golovin
sumber
Salah satu dari sedikit solusi di sini yang berfungsi tanpa elemen halaman yang melompat secara mengganggu karena overflow hidden sedang disetel.
Skeptis
+1 ini adalah solusi yang solid. jika Anda melampirkan ini ke wadah yang dapat digulir, Anda akan menginginkan div dalam contoh ini e.currentTarget.
Matt
solusi yang sangat bersih. Terima kasih
Thinh Bui
Berfungsi di Chrome 61.0.3163.100 dan Safari 11.0, tetapi tidak di FireFox 56.0 (Mac OS El Capitan)
BigJ
Ini adalah solusi asli terbaik. Namun, falsetidak perlu ditentukan addEventListenerkarena itulah defaultnya. Selain itu, perbandingannya harus berupa ketidaksetaraan sederhana ( >dan <), bukan >=atau <=.
Pertanyaan Quolonel
6

Jika saya memahami pertanyaan Anda dengan benar, maka Anda ingin mencegah pengguliran konten utama saat mouse berada di atas div (katakanlah bilah sisi). Untuk itu, sidebar mungkin bukan anak dari wadah pengguliran konten utama (yang merupakan jendela peramban), untuk mencegah acara gulir menggelembung ke induknya.

Ini mungkin memerlukan beberapa perubahan markup dengan cara berikut:

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

Lihat cara kerjanya pada contoh biola ini dan bandingkan dengan biola contoh ini yang memiliki perilaku cuti mouse yang sedikit berbeda pada bilah sisi.

Lihat juga scroll hanya satu div tertentu dengan scrollbar utama browser .

NGLN
sumber
Dalam hal ini sidebar berada di luar div pembungkus. Jadi saya tidak berpikir gulungan akan menggelembung ke induknya
Jeevan
Yang Anda maksud dengan "kasus ini" adalah kasus Anda? Jika tidak: Anda benar. Jika demikian: jika halaman Anda menggulir di akhir pengguliran div, maka pesan gulir menggelembung ke induk div, jadi menurut saya halaman dan div Anda bukan saudara kandung, tetapi induk dan anak.
NGLN
Ya, Halaman adalah induk dari div saya, Jadi saat mencapai akhir, ia mulai menggulir halaman, yang tidak saya inginkan.
Jeevan
Jika Anda tidak dapat menjadikan div Anda sebagai saudara dari konten utama, masalah ini tidak dapat diperbaiki hanya dengan HTML + CSS. Ini adalah perilaku default.
NGLN
1
Saya pikir ini adalah solusi paling efisien dari semua jawaban yang diberikan; dengan markup bersih yang baik di dasar halaman, jauh lebih sedikit peretasan CSS dan JS yang diperlukan untuk mendapatkan perilaku yang diinginkan.
6

Seperti yang dijawab di sini , sebagian besar browser modern sekarang mendukung overscroll-behavior: none;properti CSS, yang mencegah rantai gulir. Dan hanya itu, hanya satu baris!

Andriy Stolyar
sumber
2
Ini harus menjadi jawaban yang benar pada tahun 2020. Untuk kasus penggunaan saya, solusi terbaik adalah overscroll-behavior: contain;.
Dermaga
3

ini menonaktifkan pengguliran di jendela jika Anda memasukkan elemen pemilih. bekerja seperti jimat.

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");
});
ceed
sumber
Ini memang solusi yang berhasil. Saya membutuhkannya di js murni, jadi saya menulis ulang. Jika ada yang membutuhkannya, ada di sini . Bagi siapa pun yang masih mencari solusinya, Anda harus memeriksa jawaban saya di bawah ini .
Andriy Stolyar
2

Anda dapat menonaktifkan pengguliran seluruh halaman dengan melakukan hal seperti ini tetapi menampilkan bilah gulir!

<div onmouseover="document.body.style.overflow='hidden'; document.body.style.position='fixed';" onmouseout="document.body.style.overflow='auto'; document.body.style.position='relative';"></div>
joseantgv
sumber
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();
  }
});
Neil Taylor
sumber
1

Berdasarkan jawaban ceed, berikut adalah versi yang memungkinkan pengguliran bersarang elemen yang dilindungi. Hanya elemen di atas mouse yang akan menggulir, dan menggulir dengan cukup lancar. Versi ini juga peserta ulang. Ini dapat digunakan beberapa kali pada elemen yang sama dan akan dengan benar melepas dan memasang ulang penangan.

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

Salah satu cara mudah untuk menggunakan adalah dengan menambahkan kelas, seperti scroll-guard, ke semua elemen di halaman yang Anda izinkan untuk menggulir. Lalu gunakan $('.scroll-guard').scrollGuard()untuk menjaganya.

d'Artagnan Evergreen Barbosa
sumber
0

Jika Anda menerapkan overflow: hiddengaya, gaya itu akan hilang

edit: sebenarnya saya salah membaca pertanyaan Anda, itu hanya akan menyembunyikan bilah gulir tetapi menurut saya bukan itu yang Anda cari.

JavaKungFu
sumber
1
Saya membutuhkan kedua scrollbar. Saya berbicara tentang perilaku. Ketika saya menggulir menggunakan trackball mouse saya untuk mencapai ujung gulir div, itu tidak boleh menggulir seluruh halaman.
Jeevan
0

Saya tidak bisa mendapatkan jawaban apa pun untuk berfungsi di Chrome dan Firefox, jadi saya membuat penggabungan ini:

$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;
        }
    }
}
d. breve
sumber