Nhận chiều cao hiển thị của div với jQuery


86

Tôi cần truy xuất chiều cao hiển thị của một div trong một vùng có thể cuộn. Tôi tự cho mình là khá tốt với jQuery, nhưng điều này hoàn toàn khiến tôi thất vọng.

Giả sử tôi có một div màu đỏ trong một lớp bọc màu đen:

Trong hình trên, hàm jQuery sẽ trả về 248, phần hiển thị của div.

Khi người dùng cuộn qua đầu div, như trong hình trên, nó sẽ báo cáo 296.

Bây giờ, khi người dùng đã cuộn qua div, nó sẽ báo cáo lại 248.

Rõ ràng là các con số của tôi sẽ không nhất quán và rõ ràng như trong bản demo này, hoặc tôi chỉ viết mã cứng cho những con số đó.

Tôi có một chút lý thuyết:

  • Nhận chiều cao của cửa sổ
  • Lấy chiều cao của div
  • Nhận phần bù ban đầu của div từ đầu cửa sổ
  • Nhận phần bù khi người dùng cuộn.
    • Nếu độ lệch là dương, có nghĩa là đỉnh của div vẫn còn hiển thị.
    • nếu nó âm, phần trên của div đã bị cửa sổ che khuất. Tại thời điểm này, div có thể chiếm toàn bộ chiều cao của cửa sổ hoặc phần dưới cùng của div có thể hiển thị
    • Nếu đáy của div đang hiển thị, hãy tìm ra khoảng cách giữa nó và đáy của cửa sổ.

Nó có vẻ khá đơn giản, nhưng tôi không thể quấn lấy nó. Tôi sẽ lấy một vết nứt khác vào sáng mai; Tôi chỉ nghĩ rằng một số thiên tài trong số các bạn có thể giúp đỡ.

Cảm ơn!

CẬP NHẬT: Tôi đã tự mình tìm ra điều này, nhưng có vẻ như một trong những câu trả lời dưới đây thanh lịch hơn, vì vậy tôi sẽ sử dụng câu trả lời đó thay thế. Đối với những người tò mò, đây là những gì tôi nghĩ ra:

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

Tôi sẽ xem xét các đơn vị vh. 1vh = 1/100 chiều cao của khung nhìn. Bạn có thể sẽ tìm thấy một giải pháp với điều đó. Tìm chiều cao của khung nhìn, chiều cao của phần tử, vị trí của phần tử và vị trí cuộn và tính toán cho phù hợp.
davidcondrey

Giả sử có lề trên DIV bên trong, hãy nói "10px" xung quanh. Tôi sẽ phát hiện chiều cao cuộn để xem liệu nó có vượt qua "10" hay không, sau đó tôi sẽ chỉ lấy chiều cao của phần tử mẹ, trừ nó dựa trên chiều cao cuộn của nó.

Nếu vẫn thất bại, tôi chỉ đi qua kịch bản này mà trông giống như nó có thể phục vụ mục đích bạn cần: larsjung.de/fracs
davidcondrey

Câu trả lời:


57

Đây là một khái niệm nhanh chóng và bẩn thỉu. Về cơ bản, nó so sánh offset().topphần tử với phần trên cùng của cửa sổ và offset().top + height()phần dưới với phần cuối của cửa sổ:

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

Ví dụ fiddle

chỉnh sửa - cập nhật nhỏ để cũng thực hiện logic khi cửa sổ được thay đổi kích thước.


Tôi gặp sự cố khi đặt điều này cho nhiều divs mà không chỉ lặp lại mã. Có cách nào để làm việc này không?
JacobTheDev,

2
@Rev của bạn đây: jsfiddle.net/b5DGj/1 . Tôi đã tách từng phần tử để gọi hàm riêng của nó. Bạn thậm chí có thể đi xa hơn và xác định một plugin để làm điều này cho bạn.
Rory McCrossan

Tôi đã viết lại một chút cách tiếp cận của @ RoryMcCrossan để hoạt động như một plugin jQuery và đăng nó như một câu trả lời bên dưới - nó có thể có khả năng áp dụng chung hơn ở định dạng đó.
Michael.Lumley

Đôi khi một phần tử có thể bị ẩn một phần do tràn hoặc các phần tử mẹ, bất kể "cửa sổ" là gì
Nadav B

55

Tính số lượng px mà một phần tử (chiều cao) có trong khung nhìn

Bản demo Fiddle

Đây nhỏ chức năng sẽ trở lại với số lượng pxmột yếu tố có thể nhìn thấy trong (theo chiều dọc) 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));
}

Sử dụng như:

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

đó là nó.


jQuery .inViewport()Plugin

jsFiddle demo

từ phần trên, bạn có thể trích xuất logic và tạo một plugin như sau:

/**
 * 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));

Sử dụng như:

$("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

các bộ chọn của bạn sẽ tự động lắng nghe cửa sổ scrollresizeđồng thời trả về giá trị ban đầu trên DOM sẵn sàng vượt qua đối số hàm gọi lại đầu tiên px.


Để hoạt động trên Android Chrome, bạn có thể cần thêm <meta name="viewport" content="width=your_size">vào phần head html.
userlond

@userlond cảm ơn bạn đã đóng góp, nhưng tôi không chắc nó content="width=1259"có phù hợp với đa số không. Bạn đã thử content="width=device-width, initial-scale=1"thay thế chưa?
Roko C. Buljan

Trang web có mẫu kế thừa với chiều rộng cố định và không đáp ứng ... Tôi nghĩ rằng đề xuất của bạn sẽ phù hợp với đa số. Vì vậy, để làm rõ: nếu giải pháp Roko C. Buljan của không làm việc, cố gắng thêm <meta name="viewport" content="your_content">tuyên bố :)
userlond

Điều này thật tuyệt vời và quá gần với những gì tôi đã tìm kiếm. Làm cách nào để tính khoảng cách từ các phần tử dưới cùng đến cuối cửa sổ? Vì vậy, tôi có thể tải thêm nội dung trước khi bạn nhìn thấy phần cuối của nội dung. Ví dụ: nếu elBottom <200 từ windowBot, hãy kích hoạt AJAX.
Thom

1
@Thom tốt, phương thức trên không trả về bất kỳ giá trị cụ thể nào khác (nó có thể được mở rộng để trả về nhiều thứ hơn chỉ visible height px, chẳng hạn như một đối tượng. Hãy xem câu hỏi này để biết ý tưởng như vậy: jsfiddle.net/RokoCB/6xjq5gyy (mở bảng điều khiển dành cho nhà phát triển để xem nhật ký)
Roko C. Buljan

11

Đây là phiên bản của cách tiếp cận của Rory ở trên, ngoại trừ được viết để hoạt động như một plugin jQuery. Nó có thể có khả năng áp dụng chung hơn ở định dạng đó. Câu trả lời tuyệt vời, Rory - cảm ơn!

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

Có thể được gọi như sau:

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

jsFiddle


2
Không hoạt động trong trường hợp khi cửa sổ trở nên lớn hơn và khối có thể vừa vặn. Đó là lý do tại sao chúng ta cần đặt lại chiều cao khối: $ (this) .css ('height', ''); jsfiddle.net/b5DGj/144
Max
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.