web-dev-qa-db-ja.com

JavaScriptで要素が実際に表示されるかどうかを確認するにはどうすればよいですか?

JavaScriptでは、要素が実際に表示されているかどうかをどのように確認しますか?

visibility属性とdisplay属性をチェックするだけではありません。つまり、要素が

  • visibility: hiddenまたはdisplay: none
  • 別の要素の下
  • 画面の端からスクロール

技術的な理由により、スクリプトを含めることはできません。ただし、すでにページにあるように、 Prototype を使用できます。

118
Macha

ポイント2。

document.elementFromPoint(x,y)を使用することを誰も提案していないことがわかります。私にとっては、要素が別の要素によってネストされているか、隠されているかをテストする最も速い方法です。ターゲット要素のオフセットを関数に渡すことができます。

elementFromPoint のPPKテストページを次に示します。

94

私はこれがどれほど古いブラウザやそれほど近代的でないブラウザでサポートされているのかわかりませんが、私はこのようなものを使用しています(ライブラリには必要ありません):

function visible(element) {
  if (element.offsetWidth === 0 || element.offsetHeight === 0) return false;
  var height = document.documentElement.clientHeight,
      rects = element.getClientRects(),
      on_top = function(r) {
        var x = (r.left + r.right)/2, y = (r.top + r.bottom)/2;
        return document.elementFromPoint(x, y) === element;
      };
  for (var i = 0, l = rects.length; i < l; i++) {
    var r = rects[i],
        in_viewport = r.top > 0 ? r.top <= height : (r.bottom > 0 && r.bottom <= height);
    if (in_viewport && on_top(r)) return true;
  }
  return false;
}

要素の面積が0より大きいことを確認してから、要素の一部がビューポート内にあるかどうか、また別の要素の「下」に隠れていないかどうかを確認します(実際には、要素の中心の1点のみを確認、したがって、100%保証されているわけではありません-しかし、本当に必要な場合は、スクリプトを変更して要素のすべてのポイントを変更することができます...)。

更新

すべてのピクセルをチェックする修正されたon_top関数:

on_top = function(r) {
  for (var x = Math.floor(r.left), x_max = Math.ceil(r.right); x <= x_max; x++)
  for (var y = Math.floor(r.top), y_max = Math.ceil(r.bottom); y <= y_max; y++) {
    if (document.elementFromPoint(x, y) === element) return true;
  }
  return false;
};

パフォーマンスについて知らない:)

38
Tobias

Jklが指摘したように、要素の可視性または表示を確認するだけでは十分ではありません。先祖を確認する必要があります。 Seleniumは、要素の可視性を検証するときにこれを行います。

Selenium-api.jsファイルのメソッドSelenium.prototype.isVisibleを確認してください。

http://svn.openqa.org/svn/Selenium-on-Rails/Selenium-on-Rails/Selenium-core/scripts/Selenium-api.js

8
Jason Tillery

これは私がこれまで持っているものです。それは1と3の両方をカバーします。しかし、私はまだプロトタイプに精通していないので2に苦労しています(私はjQueryタイプの男です)。

function isVisible( elem ) {
    var $elem = $(elem);

    // First check if elem is hidden through css as this is not very costly:
    if ($elem.getStyle('display') == 'none' || $elem.getStyle('visibility') == 'hidden' ) {
        //elem is set through CSS stylesheet or inline to invisible
        return false;
    }

    //Now check for the elem being outside of the viewport
    var $elemOffset = $elem.viewportOffset();
    if ($elemOffset.left < 0 || $elemOffset.top < 0) {
        //elem is left of or above viewport
        return false;
    }
    var vp = document.viewport.getDimensions();
    if ($elemOffset.left > vp.width || $elemOffset.top > vp.height) {
        //elem is below or right of vp
        return false;
    }

    //Now check for elements positioned on top:
    //TODO: Build check for this using Prototype...
    //Neither of these was true, so the elem was visible:
    return true;
}
4
Pim Jager

興味深い質問。

これが私のアプローチです。

  1. 最初にelement.style.visibility!== 'hidden' && element.style.display!== 'none'を確認します
  2. 次に、返された要素が期待する要素である場合、document.elementFromPoint(element.offsetLeft、element.offsetTop)でテストします。これは、要素が別の要素と完全に重なり合っているかどうかを検出するのが難しいです。
  3. 最後に、スクロールオフセットを考慮して、offsetTopとoffsetLeftがビューポートにあるかどうかをテストします。

それが役に立てば幸い。

4

プロトタイプの 要素ライブラリ は、メソッドに関して最も強力なクエリライブラリの1つです。 APIを確認することをお勧めします。

いくつかのヒント:

  1. 可視性を確認するのは面倒ですが、Element.getStyle()メソッドとElement.visible()メソッドを組み合わせてカスタム関数を使用できます。 getStyle()を使用すると、実際の計算されたスタイルを確認できます。

  2. 「下」の意味が正確にはわかりません:)ラッパーdivなどの特定の祖先がある場合は、Element.up(cssRule)を使用できます。

    var child = $("myparagraph");
    if(!child.up("mywrapper")){
      // I lost my mom!
    }
    else {
      // I found my mom!
    }
    

    子要素の兄弟を確認する場合は、それも実行できます。

    var child = $("myparagraph");
    if(!child.previous("mywrapper")){
      // I lost my bro!
    } 
    else {
      // I found my bro!
    }
    
  3. 繰り返しますが、要素libは、あなたの意味を正しく理解している場合に役立ちます:)実際の ビューポートの寸法 および 要素のオフセット をチェックして、あなたの要素は「オフスクリーン」です。

幸運を!

Prototypejsのテストケースを http://Gist.github.com/117125 に貼り付けました。あなたの場合、getStyle()をまったく信用できないようです。 isMyElementReallyVisible関数の信頼性を最大化するには、以下を組み合わせる必要があります。

  • 計算されたスタイルの確認(dojoには、ニース 実装 借りることができます)
  • Viewportoffsetの確認(プロトタイプネイティブメソッド)
  • 「beneath」問題のz-indexを確認します(Internet Explorerではバグがある場合があります)
3
yaanno

1つの方法は次のとおりです。

isVisible(Elm) {
    while(Elm.tagName != 'BODY') {
        if(!$(Elm).visible()) return false;
        Elm = Elm.parentNode;
    }
    return true;
}

クレジット: https://github.com/atetlaw/Really-Easy-Field-Validation/blob/master/validation.js#L178

2
umpirsky

JQueryにリダイレクトするのは嫌いです(よくあることですが) ただし、この議論 要素が実際に表示される時期については非常に洞察に富んでいます。

そして jQuery 1.3.2 これは もはや問題ではない であるためです。

1
Ólafur Waage

CurrentStyle/getComputedStyleを使用している場合でも、要素#1の要素の可視性と表示プロパティをチェックするだけでは要件#1に十分ではないと思います。また、要素の祖先を確認する必要があります。祖先が非表示の場合、要素も非表示になります。

1
user176652

マウスドラッグイベントとビューポートイベント(onmouseup、onresize、onscroll)をキャッチします。

ドラッグが終了すると、ドラッグされたアイテムの境界とすべての「対象の要素」(つまり、クラス「dont_hide」またはidの配列を持つ要素)との比較を行います。 window.onscrollとwindow.onresizeでも同じことを行います。特別な属性またはクラス名で非表示の要素をマークするか、その場で必要なアクションを実行します。

隠されたテストは非常に簡単です。 「完全に非表示」の場合、すべてのコーナーがドラッグされたアイテムの境界の内側にあるか、ビューポートの外側にあるかを知りたいです。部分的に非表示にするには、同じテストに一致する単一のコーナーを探しています。

1
SpliFF

要素のoffsetHeightプロパティを確認してください。 0より大きい場合、表示されます。注:visibility:hiddenスタイルが設定されている場合、このアプローチは状況をカバーしません。しかし、とにかくそのスタイルは奇妙なものです。

0
Sergey Ilinsky

element.getBoundingClientRect()を試してください。プロパティを持つオブジェクトを返します

  • 幅-ブラウザーに依存
  • 高さ-ブラウザーに依存

要素のBoundingClientRectの幅と高さが、非表示または非表示の要素の値であるゼロでないことを確認します。値がゼロより大きい場合、要素は本体に表示されるはずです。次に、bottomプロパティがscreen.heightより小さいかどうかを確認します。これは、要素がビューポートにあることを意味します。 (技術的には、検索バー、ボタンなどを含むブラウザーウィンドウの上部も考慮する必要があります。)

0
j_v_wow_d
/**
 * Checks display and visibility of elements and it's parents
 * @param  DomElement  el
 * @param  boolean isDeep Watch parents? Default is true
 * @return {Boolean}
 *
 * @author Oleksandr Knyga <[email protected]>
 */
function isVisible(el, isDeep) {
    var elIsVisible = true;

    if("undefined" === typeof isDeep) {
        isDeep = true;
    }

    elIsVisible = elIsVisible && el.offsetWidth > 0 && el.offsetHeight > 0;

    if(isDeep && elIsVisible) {

        while('BODY' != el.tagName && elIsVisible) {
            elIsVisible = elIsVisible && 'hidden' != window.getComputedStyle(el).visibility;
            el = el.parentElement;
        }
    }

    return elIsVisible;
}
0
Oleksandr Knyga

サンプルスクリプトとテストケースを次に示します。配置された要素、可視性:非表示、表示:なしをカバーします。 z-indexをテストしませんでした。動作すると仮定します。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
  <head>
    <title></title>
    <style type="text/css">
    div {
      width: 200px;
      border: 1px solid red;
    }
    p {
      border: 2px solid green;
    }
    .r {
      border: 1px solid #BB3333;
      background: #EE9999;
      position: relative;
      top: -50px;
      height: 2em;
    }
    .of {
      overflow: hidden;
      height: 2em;
      Word-wrap: none; 
    }
    .of p {
      width: 100%;
    }

    .of pre {
      display: inline;
    }
    .iv {
      visibility: hidden;
    }
    .dn {
      display: none;
    }
    </style>
    <script src="http://www.prototypejs.org/assets/2008/9/29/prototype-1.6.0.3.js"></script>
    <script>
      function isVisible(elem){
        if (Element.getStyle(elem, 'visibility') == 'hidden' || Element.getStyle(elem, 'display') == 'none') {
          return false;
        }
        var topx, topy, botx, boty;
        var offset = Element.positionedOffset(elem);
        topx = offset.left;
        topy = offset.top;
        botx = Element.getWidth(elem) + topx;
        boty = Element.getHeight(elem) + topy;
        var v = false;
        for (var x = topx; x <= botx; x++) {
          for(var y = topy; y <= boty; y++) {
            if (document.elementFromPoint(x,y) == elem) {
              // item is visible
              v = true;
              break;
            }
          }
          if (v == true) {
            break;
          }
        }
        return v;
      }

      window.onload=function() {
        var es = Element.descendants('body');
        for (var i = 0; i < es.length; i++ ) {
          if (!isVisible(es[i])) {
            alert(es[i].tagName);
          }
        }
      }
    </script>
  </head>
  <body id='body'>
    <div class="s"><p>This is text</p><p>More text</p></div>
    <div class="r">This is relative</div>
    <div class="of"><p>This is too wide...</p><pre>hidden</pre>
    <div class="iv">This is invisible</div>
    <div class="dn">This is display none</div>
  </body>
</html>

ClientHeightまたはclientWidthプロパティを使用できます

function isViewable(element){
  return (element.clientHeight > 0);
}
0
fred