127

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

visibilitydisplay属性をチェックするだけではありません。つまり、要素がそうではないことを確認します

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

技術的な理由から、スクリプトを含めることはできません。ただし、すでにページにあるので、プロトタイプを使用できます。

4

15 に答える 15

40

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

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

パフォーマンスについてはわかりません:)

于 2009-10-09T10:00:07.307 に答える
7

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

于 2010-05-17T06:39:19.867 に答える
4

興味深い質問です。

これが私のアプローチになります。

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

それが役に立てば幸い。

于 2009-05-24T18:33:39.683 に答える
3

これは私がこれまでに持っているものです。それは1と3の両方をカバーしています。しかし、私はPrototypeにあまり詳しくないので、まだ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;
}
于 2009-05-24T15:47:18.703 に答える
2

Prototype のElement ライブラリは、メソッドに関して最も強力なクエリ ライブラリの 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. 繰り返しますが、あなたの意味を正しく理解していれば、要素ライブラリが役立ちます:)ビューポートの実際の寸法と要素のオフセットを確認して、要素が「画面外」であるかどうかを計算できます。

幸運を!

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

  • 計算されたスタイルの確認 (Dojo には借用できる優れた実装があります)
  • viewportoffset の確認 (プロトタイプ ネイティブ メソッド)
  • 「下」の問題について z-index をチェックします (Internet Explorer ではバグがある可能性があります)。
于 2009-05-23T19:47:41.380 に答える
1

それを行う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

于 2011-09-12T06:54:55.207 に答える
1

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

function isViewable(element){
  return (element.clientHeight > 0);
}
于 2014-02-13T14:33:44.627 に答える
1

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

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

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

于 2014-06-05T05:13:12.103 に答える
1
/**
 * 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 <oleksandrknyga@gmail.com>
 */
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;
}
于 2014-02-11T16:07:18.517 に答える
0

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

于 2009-09-21T16:16:05.597 に答える
0

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

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

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

于 2009-05-24T14:13:56.450 に答える
-1

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

于 2009-04-01T09:34:15.007 に答える
-1

サンプル スクリプトとテスト ケースを次に示します。配置された要素をカバーします。可視性: 非表示、表示: なし。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>
于 2009-05-25T15:45:19.083 に答える