jQueryを使用してdivの表示される高さを取得します


86

スクロール可能な領域内のdivの表示されている高さを取得する必要があります。私は自分自身をjQueryでかなりまともだと思っていますが、これは完全に私を失望させています。

黒のラッパー内に赤のdivがあるとしましょう:

上の図では、jQuery関数はdivの表示部分である248を返します。

上の図のように、ユーザーがdivの上部を超えてスクロールすると、296が報告されます。

これで、ユーザーがdivを超えてスクロールすると、再び248が報告されます。

明らかに、私の番号はこのデモのように一貫性があり明確ではないか、またはそれらの番号をハードコーディングするだけです。

私には少し理論があります:

  • ウィンドウの高さを取得します
  • divの高さを取得します
  • ウィンドウの上部からdivの初期オフセットを取得します
  • ユーザーがスクロールするときにオフセットを取得します。
    • オフセットが正の場合、divの上部がまだ表示されていることを意味します。
    • 負の場合、divの上部がウィンドウによって隠されています。この時点で、divがウィンドウの高さ全体を占めるか、divの下部が表示されている可能性があります。
    • divの下部が表示されている場合は、divとウィンドウの下部との間のギャップを把握します。

とてもシンプルに見えますが、頭を包むことができません。明日の朝、またひびを入れます。私はちょうどあなたの天才の何人かが助けることができるかもしれないと思いました。

ありがとう!

更新:私はこれを自分で理解しましたが、以下の答えの1つがよりエレガントであるように見えるので、代わりにそれを使用します。好奇心旺盛な方のために、私が思いついたものは次のとおりです。

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

私はvhユニットを調べます。1vh =ビューポートの高さの1/100。あなたはおそらくそれで解決策を見つけるでしょう。ビューポートの高さ、要素の高さ、要素の位置、およびスクロール位置を見つけて、それに応じて計算します。
davidcondrey 2014

内側のDIVにマージンがあると仮定して、全体に「10px」と言います。スクロールの高さを検出して「10」を通過したかどうかを確認し、親要素の高さを取得して、スクロールの高さに基づいて減算します。

他のすべてが失敗した場合、私はちょうどあなたが必要とする目的を果たすかもしれないように見えるこのスクリプトに出くわしました:larsjung.de/fracs
davidcondrey 2014

回答:


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

フィドルの例

編集-ウィンドウのサイズが変更されているときにロジックも実行するための小さな更新。


divコードを繰り返さずにこれを複数のsに設定するのに問題があります。これを行う方法はありますか?
JacobTheDev 2014

2
@Rev here you go:jsfiddle.net/b5DGj/1。各要素を独自の関数呼び出しに分離しました。さらに進んで、プラグインを定義してこれを行うこともできます。
Rory McCrossan 2014

@RoryMcCrossanのjQueryプラグインとして機能するアプローチを少し書き直し、以下の回答として投稿しました。この形式では、より一般的な適用性がある可能性があります。
Michael.Lumley 2015

「ウィンドウ」に関係なく、オーバーフローまたは親要素のために要素が部分的に非表示になる場合があります
NadavB19年

55

要素(高さ)がビューポートにあるpxの量を計算します

フィドルデモ

この小さな関数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
});

それでおしまい。


jQuery.inViewport()プラグイン

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">headhtmlセクションに追加する必要がある場合があります。
userlond 2016

@userlondの貢献に感謝しますがcontent="width=1259"、大多数に適しているかどうかはわかりません。content="width=device-width, initial-scale=1"代わりに試しましたか?
Roko C. Buljan 2016

サイトには固定幅のレガシーテンプレートがあり、応答しません...あなたの提案は大多数にとって大丈夫だと思います。明確にするために:Roko C. Buljanのソリューションが機能しない場合は、<meta name="viewport" content="your_content">宣言を追加してみてください:)
userlond 2016

これはとても素晴らしく、私が探していたものにとても近いです。要素の下部からウィンドウの下部までの距離を計算するにはどうすればよいですか?そのため、コンテンツの終わりが表示される前に、さらにコンテンツを読み込むことができます。たとえば、windowBotからelBottom <200の場合、AJAXを起動します。
トム2017

1
@Thomええと、上記のメソッドは他の特定の値を返しません(visible height pxオブジェクトなど、単なるオブジェクト以外のものを返すように拡張できます。そのようなアイデアについては、次のフィドルを参照してください:jsfiddle.net/RokoCB/6xjq5gyy(開発者コンソールを開く)ログを表示するには)
Roko C. Buljan 2017

11

これは、jQueryプラグインとして機能するように記述されていることを除いて、上記のRoryのアプローチのバージョンです。その形式では、より一般的な適用性がある可能性があります。素晴らしい答え、ロリー-ありがとう!

$.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
Max Koshel 2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.