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

86

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

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

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

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

Теперь, когда пользователь прокручивает 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);
        }
    }
});
JacobTheDev
источник
Я бы посмотрел на единицы vh. 1vh = 1/100 высоты окна просмотра. Вы, вероятно, найдете в этом решение. Найдите высоту области просмотра, высоту элемента, положение элементов и положение прокрутки и рассчитайте соответственно.
davidcondrey
Предполагая, что на внутреннем DIV есть поле, скажите «10 пикселей» по всему периметру. Я бы определил высоту прокрутки, чтобы увидеть, прошло ли она «10», тогда я бы просто получил высоту родительского элемента, вычтите ее в зависимости от высоты прокрутки.
Если ничего не
помогает

Ответы:

57

Вот такая быстрая и грязная концепция. Он в основном сравнивает 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 - небольшое обновление, чтобы также выполнять логику при изменении размера окна.

Рори МакКроссан
источник
У меня возникли проблемы с установкой этого для нескольких divs без простого повторения кода. Есть ли способ сделать это?
JacobTheDev
2
@Rev, пожалуйста: jsfiddle.net/b5DGj/1 . Я разделил каждый элемент на отдельный вызов функции. Вы даже можете пойти дальше и определить плагин, который сделает это за вас.
Рори МакКроссан
Я немного переписал подход @RoryMcCrossan к работе в качестве плагина jQuery и опубликовал его в качестве ответа ниже - он может иметь более общее применение в этом формате.
Майкл Ламли
Иногда элемент может быть частично скрыт из-за переполнения или родительских элементов, независимо от «окна»
Надав Б.
55

Вычислить количество пикселей (высоту) в области просмотра в пикселях

Демо скрипки

Эта крошечная функция вернет количество 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) : Math.min(b, H));
}

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

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

вот и все.


.inViewport()Плагин jQuery

демонстрация jsFiddle

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

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

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

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

Роко С. Бульян
источник
Для работы в Android Chrome вам может потребоваться добавить <meta name="viewport" content="width=your_size">в заголовок раздел html.
userlond
@userlond спасибо за ваш вклад, но я не уверен, content="width=1259"что он подойдет большинству. Вы пробовали content="width=device-width, initial-scale=1"вместо этого?
Roko C. Buljan
Сайт имеет устаревший шаблон с фиксированной шириной и не реагирует на запросы ... Я думаю, что ваш вариант подойдет большинству. Итак, чтобы уточнить: если решение Roko C. Buljan не работает, попробуйте добавить <meta name="viewport" content="your_content">объявление :)
userlond
Это так здорово и так близко к тому, что я искал. Как я могу рассчитать расстояние от низа элементов до низа окна? Так что я могу загрузить больше контента, прежде чем вы увидите конец контента. Например, если elBottom <200 из windowBot, запустить AJAX.
Thom
1
@Thom ну, вышеупомянутый метод не возвращает никаких других конкретных значений (его можно расширить, чтобы вернуть больше вещей, чем просто visible height pxобъект, например объект. См. Эту скрипку для такой идеи: jsfiddle.net/RokoCB/6xjq5gyy (открытая консоль разработчика для просмотра журналов)
Roko C. Buljan
11

Вот версия подхода Рори, описанного выше, за исключением того, что он написан для работы как плагин 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

Майкл Ламли
источник
2
Не работать, если окно становится больше и блок может уместиться. Вот почему нам нужно сбросить высоту блока: $ (this) .css ('height', ''); jsfiddle.net/b5DGj/144
Макс Кошель