Ermitteln Sie mit jQuery die sichtbare Höhe eines Div

86

Ich muss die sichtbare Höhe eines Div innerhalb eines scrollbaren Bereichs abrufen. Ich halte mich mit jQuery für ziemlich anständig, aber das macht mich total fertig.

Angenommen, ich habe eine rote Div in einer schwarzen Hülle:

In der obigen Grafik würde die jQuery-Funktion 248, den sichtbaren Teil des div, zurückgeben.

Sobald der Benutzer wie in der obigen Grafik über den oberen Rand des div gescrollt hat, meldet er 296.

Sobald der Benutzer über das div gescrollt hat, meldet er erneut 248.

Offensichtlich werden meine Zahlen nicht so konsistent und klar sein wie in dieser Demo, oder ich würde nur hart für diese Zahlen codieren.

Ich habe eine Theorie:

  • Holen Sie sich die Höhe des Fensters
  • Holen Sie sich die Höhe der div
  • Holen Sie sich den anfänglichen Versatz des div vom oberen Rand des Fensters
  • Holen Sie sich den Offset, während der Benutzer einen Bildlauf durchführt.
    • Wenn der Versatz positiv ist, bedeutet dies, dass die Oberseite des Div noch sichtbar ist.
    • Wenn es negativ ist, wurde die Oberseite des Div durch das Fenster verdeckt. Zu diesem Zeitpunkt könnte das Div entweder die gesamte Höhe des Fensters einnehmen oder der Boden des Div könnte angezeigt werden
    • Wenn die Unterseite des Div angezeigt wird, ermitteln Sie die Lücke zwischen der Div und der Unterseite des Fensters.

Es scheint ziemlich einfach zu sein, aber ich kann meinen Kopf einfach nicht darum wickeln. Ich werde morgen früh einen weiteren Sprung machen; Ich dachte nur, einige von euch Genies könnten helfen.

Vielen Dank!

UPDATE: Ich habe das selbst herausgefunden, aber es sieht so aus, als wäre eine der folgenden Antworten eleganter, also werde ich das stattdessen verwenden. Für die Neugierigen habe ich mir Folgendes ausgedacht:

$(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
quelle
Ich würde in vh Einheiten schauen. 1vh = 1/100 der Höhe des Ansichtsfensters. Damit finden Sie wahrscheinlich eine Lösung. Suchen Sie die Höhe des Ansichtsfensters, die Höhe des Elements, die Elementposition und die Bildlaufposition und berechnen Sie entsprechend.
Davidcondrey
Angenommen, der innere DIV hat einen Rand, sagen Sie ringsum "10px". Ich würde die Bildlaufhöhe ermitteln, um zu sehen, ob "10" überschritten wird. Dann würde ich nur die Höhe des übergeordneten Elements ermitteln und es anhand der Bildlaufhöhe subtrahieren.
Wenn alles andere fehlschlägt, bin ich gerade auf dieses Skript gestoßen,
davidcondrey

Antworten:

57

Hier ist ein schnelles und schmutziges Konzept. Grundsätzlich wird offset().topdas Element mit dem oberen offset().top + height()Rand des Fensters und dem unteren Rand des Fensters verglichen :

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

Beispiel Geige

edit - kleines Update, um auch die Logik auszuführen, wenn die Fenstergröße geändert wird.

Rory McCrossan
quelle
Ich habe Probleme, dies für mehrere divs einzustellen, ohne nur den Code zu wiederholen. Gibt es eine Möglichkeit, dies zu tun?
JacobTheDev
2
@Rev hier geht's: jsfiddle.net/b5DGj/1 . Ich habe jedes Element in einen eigenen Funktionsaufruf unterteilt. Sie können sogar noch weiter gehen und ein Plugin definieren, das dies für Sie erledigt.
Rory McCrossan
Ich habe den Ansatz von @ RoryMcCrossan, als jQuery-Plugin zu fungieren, leicht umgeschrieben und als Antwort unten veröffentlicht - er kann in diesem Format allgemeiner anwendbar sein.
Michael.Lumley
Manchmal kann ein Element aufgrund von Überlauf oder übergeordneten Elementen teilweise ausgeblendet werden, unabhängig vom "Fenster"
Nadav B
54

Berechnen Sie die Menge an px, die sich ein Element (Höhe) im Ansichtsfenster befindet

Geigen-Demo

Diese winzige Funktion gibt die Menge pxeines Elements zurück, die im (vertikalen) Ansichtsfenster sichtbar ist :

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

Verwenden Sie wie:

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

das ist es.


jQuery .inViewport()Plugin

jsFiddle-Demo

Von oben können Sie die Logik extrahieren und ein Plugin wie dieses erstellen:

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

Verwenden Sie wie:

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

Ihre Selektoren hören das Fenster dynamisch ab scrollund geben resizeüber den ersten Rückruffunktionsargument auch den Anfangswert für DOM bereit zurück px.

Roko C. Buljan
quelle
Um mit Android Chrome arbeiten zu können, müssen Sie möglicherweise den <meta name="viewport" content="width=your_size">HTML-Abschnitt head hinzufügen .
Userlond
@userlond danke für deinen Beitrag, aber ich bin mir nicht sicher, ob er content="width=1259"für die Mehrheit geeignet ist . Hast du es content="width=device-width, initial-scale=1"stattdessen versucht ?
Roko C. Buljan
Die Site hat eine Legacy-Vorlage mit fester Breite und reagiert nicht ... Ich denke, dass Ihr Vorschlag für die Mehrheit in Ordnung ist. Um dies zu verdeutlichen: Wenn die Lösung von Roko C. Buljan nicht funktioniert, versuchen Sie, eine <meta name="viewport" content="your_content">Erklärung hinzuzufügen :)
userlond
Das ist so großartig und so nah an dem, wonach ich gesucht habe. Wie kann ich den Abstand zwischen den Elementen unten und unten im Fenster berechnen? So kann ich mehr Inhalte laden, bevor Sie das Ende des Inhalts sehen. Wenn beispielsweise elBottom <200 von windowBot ist, feuern Sie AJAX ab.
Thom
1
@Thom gut, die obige Methode gibt keine anderen spezifischen Werte zurück (sie kann erweitert werden, um mehr Material als nur visible height pxein Objekt zurückzugeben. Eine solche Idee finden Sie in dieser Geige: jsfiddle.net/RokoCB/6xjq5gyy (Entwicklerkonsole öffnen) um die Protokolle zu sehen)
Roko C. Buljan
11

Hier ist eine Version von Rorys Ansatz oben, außer dass sie als jQuery-Plugin geschrieben wurde. Es kann allgemeinere Anwendbarkeit in diesem Format haben. Tolle Antwort, Rory - danke!

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

Kann mit folgendem Aufruf aufgerufen werden:

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

jsFiddle

Michael.Lumley
quelle
2
Arbeiten Sie nicht, wenn das Fenster größer wird und der Block passt. Deshalb müssen wir die Blockhöhe zurücksetzen: $ (this) .css ('height', ''); jsfiddle.net/b5DGj/144
Max Koshel