JavaScript では、要素が実際に表示されているかどうかをどのように確認しますか?
visibility
とdisplay
属性をチェックするだけではありません。つまり、要素がそうではないことを確認します
visibility: hidden
またdisplay: none
- 別の要素の下
- 画面の端からスクロールした
技術的な理由から、スクリプトを含めることはできません。ただし、すでにページにあるので、プロトタイプを使用できます。
JavaScript では、要素が実際に表示されているかどうかをどのように確認しますか?
visibility
とdisplay
属性をチェックするだけではありません。つまり、要素がそうではないことを確認します
visibility: hidden
またdisplay: none
技術的な理由から、スクリプトを含めることはできません。ただし、すでにページにあるので、プロトタイプを使用できます。
これが古いブラウザやそれほど現代的ではないブラウザでどの程度サポートされているかはわかりませんが、次のようなものを使用しています(ライブラリは必要ありません):
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;
};
パフォーマンスについてはわかりません:)
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
興味深い質問です。
これが私のアプローチになります。
それが役に立てば幸い。
これは私がこれまでに持っているものです。それは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;
}
Prototype のElement ライブラリは、メソッドに関して最も強力なクエリ ライブラリの 1 つです。APIをチェックアウトすることをお勧めします。
いくつかのヒント:
Element.getStyle()
可視性を確認するのは面倒ですが、メソッドとElement.visible()
メソッドをカスタム関数に組み合わせて使用できます。実際に計算されたスタイルをgetStyle()
確認できます。
「下」の意味が正確にはわかりません:)ラッパー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!
}
繰り返しますが、あなたの意味を正しく理解していれば、要素ライブラリが役立ちます:)ビューポートの実際の寸法と要素のオフセットを確認して、要素が「画面外」であるかどうかを計算できます。
幸運を!
http://gist.github.com/117125に、prototypejs のテスト ケースを貼り付けました。あなたの場合、私たちはまったく信頼できないgetStyle()
ようです。isMyElementReallyVisible 関数の信頼性を最大化するには、以下を組み合わせる必要があります。
それを行う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
clientHeight または clientWidth プロパティを使用できます
function isViewable(element){
return (element.clientHeight > 0);
}
試してみてくださいelement.getBoundingClientRect()
。プロパティを持つオブジェクトを返します
要素の幅と高さがBoundingClientRect
非表示要素または非表示要素の値であるゼロでないことを確認してください。値が 0 より大きい場合、要素は本文に表示されます。次に、bottom
プロパティがより小さいかどうかを確認しますscreen.height
。これは、要素がビューポート内にあることを意味します。(技術的には、検索バーやボタンなどを含むブラウザ ウィンドウの上部も考慮する必要があります)。
/**
* 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;
}
currentStyle/getComputedStyle を使用したとしても、要素自体の可視性と表示プロパティをチェックするだけでは要件 1 には十分ではないと思います。要素の祖先も確認する必要があります。先祖が隠されている場合、要素も隠されています。
マウス ドラッグおよびビューポート イベント (onmouseup、onresize、onscroll) をキャッチします。
ドラッグが終了すると、ドラッグされたアイテムの境界とすべての「対象の要素」(つまり、クラス「dont_hide」または ID の配列を持つ要素) との比較が行われます。window.onscroll と window.onresize で同じことを行います。特別な属性またはクラス名で非表示の要素をマークするか、必要なアクションをその場で実行します。
非表示のテストは非常に簡単です。「完全に非表示」の場合、すべてのコーナーがドラッグされたアイテムの境界の内側にあるか、ビューポートの外側にあるかを知りたいです。部分的に非表示の場合、同じテストに一致する単一のコーナーを探しています。
要素の offsetHeight プロパティを確認してください。0 より大きい場合は表示されます。注: このアプローチは、 Visibility:hidden スタイルが設定されている場合には対応していません。しかし、そのスタイルはとにかく奇妙なものです。
サンプル スクリプトとテスト ケースを次に示します。配置された要素をカバーします。可視性: 非表示、表示: なし。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>