Получите видимую высоту div с помощью jQuery

Мне нужно получить видимую высоту div в пределах прокручиваемой области. Я считаю себя довольно приличным с jQuery, но это полностью отбрасывает меня.

Скажем, у меня есть красный div в черной обертке:

oiFk3n4.png

На графике выше функция jQuery вернет 248, видимую часть div.

qzHJLZo.png

Как только пользователь прокручивает верхнюю часть div, как и в приведенном выше графике, он сообщает 296.

m8lkMcj.png

Теперь, как только пользователь прокрутит прокрутку div, он снова сообщит об этом 248.

Очевидно, что мои номера не будут такими же четкими и ясными, как в этой демонстрации, или я бы просто написал код для этих чисел.

У меня есть немного теории:

  • Получить высоту окна
  • Получить высоту div
  • Получить начальное смещение div из верхней части окна
  • Получить смещение, когда пользователь прокручивает.
    • Если смещение положительное, это означает, что верхняя часть div все еще видна.
    • Если он отрицательный, верхняя часть div затмевается окном. На этом этапе div может либо занимать всю высоту окна, либо нижняя часть div может показывать
    • Если нижняя часть div отображается, найдите промежуток между ним и нижней частью окна.

Это кажется довольно простым, но я просто не могу обернуть вокруг него голову. Завтра утром я сделаю очередной треск; Я просто подумал, что некоторые из вас, гениев, могут помочь.

Спасибо!

ОБНОВЛЕНИЕ: Я понял это самостоятельно, но похоже, что один из ответов ниже более изящный, поэтому я буду использовать это вместо этого. Для любопытных, вот что я придумал:

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

Ответ 1

Вот быстрая и грязная концепция. Он в основном сравнивает offset().top элемента с вершиной окна, а offset().top + height() - в нижней части окна:

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

Пример скрипта

edit - небольшое обновление, которое также выполняет логику при изменении размера окна.

Ответ 2

Рассчитайте количество пикселей, которое элемент (высота) находится в окне просмотра

Скриншот демо

Эта маленькая функция, которую я создал, вернет количество px, элемент будет виден в (вертикальном) видовом экране:

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) : (b<H?b:H));
}

Используйте как:

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

, чтобы он.


jQuery .inViewport() Плагин

jsFiddle demo

из вышесказанного вы можете извлечь логику и создать такой плагин, как этот:

/**
 * 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) : (b<H?b:H)));  
       }
       visPx();
       $(win).on("resize scroll", visPx);
     });
  };
}(jQuery, window));

Использовать как:

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

ваши селекторы будут динамически слушать окна scroll и resize, но также возвращать начальное значение в DOM, готовое через первый аргумент функции обратного вызова px.

Ответ 3

Ниже приведена версия подхода Рори, за исключением того, что она написана как плагин jQuery. Он может иметь более общую применимость в этом формате. Отличный ответ, Рори - спасибо!

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

Можно вызвать со следующим:

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

jsFiddle