Dapatkan ketinggian div yang terlihat dengan jQuery

87

Saya perlu mengambil ketinggian div yang terlihat dalam area yang dapat digulir. Saya menganggap diri saya cukup baik dengan jQuery, tetapi ini benar-benar membuat saya marah.

Katakanlah saya punya div merah di dalam bungkus hitam:

Dalam grafik di atas, fungsi jQuery akan mengembalikan 248, bagian div yang terlihat.

Setelah pengguna menggulir melewati bagian atas div, seperti pada grafik di atas, ini akan melaporkan 296.

Sekarang, setelah pengguna menggulir melewati div, itu akan melaporkan lagi 248.

Jelas nomor saya tidak akan sekonsisten dan sejelas di demo ini, atau saya hanya kode keras untuk nomor-nomor itu.

Saya punya sedikit teori:

  • Dapatkan ketinggian jendela
  • Dapatkan ketinggian div
  • Dapatkan offset awal div dari bagian atas jendela
  • Dapatkan offset saat pengguna menggulir.
    • Jika offsetnya positif, itu berarti bagian atas div masih terlihat.
    • jika negatif, bagian atas div telah terhalang oleh jendela. Pada titik ini, div bisa saja memenuhi seluruh tinggi jendela, atau bagian bawah div bisa ditampilkan
    • Jika bagian bawah div muncul, cari tahu jarak antara div dan bagian bawah jendela.

Tampaknya cukup sederhana, tetapi saya tidak bisa membungkus kepalaku di sekitarnya. Saya akan mengambil celah lagi besok pagi; Saya baru saja membayangkan beberapa dari Anda yang jenius mungkin bisa membantu.

Terima kasih!

PEMBARUAN: Saya menemukan ini sendiri, tetapi sepertinya salah satu jawaban di bawah ini lebih elegan, jadi saya akan menggunakan itu sebagai gantinya. Bagi yang penasaran, inilah yang saya temukan:

$(document).ready(function() {
    var windowHeight = $(window).height();
    var overviewHeight = $("#overview").height();
    var overviewStaticTop = $("#overview").offset().top;
    var overviewScrollTop = overviewStaticTop - $(window).scrollTop();
    var overviewStaticBottom = overviewStaticTop + $("#overview").height();
    var overviewScrollBottom = windowHeight - (overviewStaticBottom - $(window).scrollTop());
    var visibleArea;
    if ((overviewHeight + overviewScrollTop) < windowHeight) {
        // alert("bottom is showing!");
        visibleArea = windowHeight - overviewScrollBottom;
        // alert(visibleArea);
    } else {
        if (overviewScrollTop < 0) {
            // alert("is full height");
            visibleArea = windowHeight;
            // alert(visibleArea);
        } else {
            // alert("top is showing");
            visibleArea = windowHeight - overviewScrollTop;
            // alert(visibleArea);
        }
    }
});
JacobTheDev
sumber
Saya akan melihat ke unit vh. 1vh = 1/100 tinggi viewport. Anda mungkin akan menemukan solusi dengan itu. Temukan tinggi area pandang, tinggi elemen, posisi elemen, dan posisi gulir, lalu hitung sesuai.
davidcondrey
Dengan asumsi ada margin di DIV bagian dalam, ucapkan "10 piksel" di sekelilingnya. Saya akan mendeteksi tinggi gulungan untuk melihat apakah itu melewati "10", maka saya hanya akan mendapatkan tinggi dari elemen induk, menguranginya berdasarkan tinggi gulungannya.
Jika semuanya gagal, saya baru saja menemukan skrip ini yang sepertinya dapat memenuhi tujuan yang Anda butuhkan: larsjung.de/fracs
davidcondrey

Jawaban:

58

Inilah konsep cepat dan kotor. Ini pada dasarnya membandingkan offset().topelemen ke bagian atas jendela, dan offset().top + height()ke bagian bawah jendela:

function getVisible() {    
    var $el = $('#foo'),
        scrollTop = $(this).scrollTop(),
        scrollBot = scrollTop + $(this).height(),
        elTop = $el.offset().top,
        elBottom = elTop + $el.outerHeight(),
        visibleTop = elTop < scrollTop ? scrollTop : elTop,
        visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
    $('#notification').text(visibleBottom - visibleTop);
}

$(window).on('scroll resize', getVisible);

Contoh biola

edit - pembaruan kecil untuk juga menjalankan logika saat jendela diubah ukurannya.

Rory McCrossan
sumber
Saya mengalami masalah saat menyetel ini untuk beberapa divd tanpa hanya mengulangi kode. Apakah ada cara untuk melakukan ini?
JacobTheDev
2
@Rev ini dia: jsfiddle.net/b5DGj/1 . Saya memisahkan setiap elemen untuk pemanggilan fungsinya sendiri. Anda bahkan dapat melangkah lebih jauh dan menentukan plugin untuk melakukan ini untuk Anda.
Rory McCrossan
Saya sedikit menulis ulang pendekatan @ RoryMcCrossan untuk berfungsi sebagai plugin jQuery dan mempostingnya sebagai jawaban di bawah - ini mungkin memiliki penerapan yang lebih umum dalam format itu.
Michael. Lumley
Terkadang sebuah elemen dapat disembunyikan sebagian karena overflow atau elemen induk, terlepas dari "jendela"
Nadav B
56

Hitung jumlah piksel elemen (tinggi) di viewport

Demo biola

Fungsi kecil ini akan mengembalikan jumlah pxelemen yang terlihat di (vertikal) Viewport :

function inViewport($el) {
    var elH = $el.outerHeight(),
        H   = $(window).height(),
        r   = $el[0].getBoundingClientRect(), t=r.top, b=r.bottom;
    return Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H));
}

Gunakan seperti:

$(window).on("scroll resize", function(){
  console.log( inViewport($('#elementID')) ); // n px in viewport
});

itu dia.


.inViewport()Plugin jQuery

jsFiddle demo

dari atas Anda dapat mengekstrak logika dan membuat plugin seperti ini:

/**
 * inViewport jQuery plugin by Roko C.B.
 * http://stackoverflow.com/a/26831113/383904
 * Returns a callback function with an argument holding
 * the current amount of px an element is visible in viewport
 * (The min returned value is 0 (element outside of viewport)
 */
;(function($, win) {
  $.fn.inViewport = function(cb) {
     return this.each(function(i,el) {
       function visPx(){
         var elH = $(el).outerHeight(),
             H = $(win).height(),
             r = el.getBoundingClientRect(), t=r.top, b=r.bottom;
         return cb.call(el, Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H)));  
       }
       visPx();
       $(win).on("resize scroll", visPx);
     });
  };
}(jQuery, window));

Gunakan seperti:

$("selector").inViewport(function(px) {
  console.log( px ); // `px` represents the amount of visible height
  if(px > 0) {
    // do this if element enters the viewport // px > 0
  }else{
    // do that if element exits  the viewport // px = 0
  }
}); // Here you can chain other jQuery methods to your selector

pemilih Anda akan secara dinamis mendengarkan window scrolldan resizejuga mengembalikan nilai awal pada siap DOM melalui argumen fungsi callback pertama px.

Roko C. Buljan
sumber
Untuk bekerja di Android Chrome Anda mungkin perlu menambahkan <meta name="viewport" content="width=your_size">ke bagian kepala html.
userlond
@userlond terima kasih atas kontribusi Anda, tetapi saya tidak yakin content="width=1259"mungkin cocok untuk mayoritas. Sudahkah Anda mencoba content="width=device-width, initial-scale=1"?
Roko C. Buljan
Situs memiliki templat lama dengan lebar tetap dan tidak responsif ... Saya pikir saran Anda akan baik-baik saja untuk mayoritas. Jadi untuk memperjelas: jika solusi Roko C. Buljan tidak berhasil, coba tambahkan <meta name="viewport" content="your_content">deklarasi :)
userlond
Ini sangat mengagumkan dan sangat dekat dengan apa yang saya cari selama ini. Bagaimana cara menghitung jarak dari elemen bawah ke bagian bawah jendela? Jadi saya dapat memuat lebih banyak konten sebelum Anda melihat akhir konten. Misalnya, jika elBottom <200 from windowBot, aktifkan AJAX.
Thom
1
@Thom well, metode di atas tidak mengembalikan nilai spesifik lainnya (ini dapat diperluas untuk mengembalikan lebih banyak barang daripada hanya visible height px, seperti objek. Lihat biola ini untuk ide seperti itu: jsfiddle.net/RokoCB/6xjq5gyy (buka konsol pengembang untuk melihat log)
Roko C. Buljan
11

Berikut adalah versi pendekatan Rory di atas, kecuali ditulis untuk berfungsi sebagai plugin jQuery. Ini mungkin memiliki penerapan yang lebih umum dalam format itu. Jawaban bagus, Rory - terima kasih!

$.fn.visibleHeight = function() {
    var elBottom, elTop, scrollBot, scrollTop, visibleBottom, visibleTop;
    scrollTop = $(window).scrollTop();
    scrollBot = scrollTop + $(window).height();
    elTop = this.offset().top;
    elBottom = elTop + this.outerHeight();
    visibleTop = elTop < scrollTop ? scrollTop : elTop;
    visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
    return visibleBottom - visibleTop
}

Bisa disebut dengan yang berikut:

$("#myDiv").visibleHeight();

jsFiddle

Michael. Lumley
sumber
2
Jangan bekerja jika jendela menjadi lebih besar dan blok bisa muat. Itulah mengapa kita perlu mengatur ulang tinggi blok: $ (this) .css ('height', ''); jsfiddle.net/b5DGj/144
Max Koshel