IT

요소가 DOM에 보이는지 확인

lottoking 2020. 3. 8. 16:27
반응형

요소가 DOM에 보이는지 확인


순수 JS (jQuery 없음)에서 요소가 표시되는지 확인할 수있는 방법이 있습니까?

따라서 예를 들어 Performance Bikes 페이지에서 거래 (상단 메뉴의 거래) 위로 마우스를 가져 가면 거래 창이 표시되지만 처음에는 표시되지 않았습니다. HTML에 있지만 표시되지 않습니다.

따라서 DOM 요소가 주어지면 표시 여부를 어떻게 확인할 수 있습니까? 나는 시도했다 :

window.getComputedStyle(my_element)['display']);

하지만 작동하지 않는 것 같습니다. 어떤 속성을 확인해야하는지 궁금합니다. 내 마음에 온다 :

display !== 'none'
visibility !== 'hidden'

내가 잃어버린 다른 사람이 있습니까?


이 MDN documentation 에 따르면 요소 또는 그 부모가 표시 스타일 속성을 통해 숨겨 질 때마다 요소의 offsetParent속성이 반환 null됩니다. 요소가 고정되어 있지 않은지 확인하십시오. position: fixed;페이지에 요소 가없는 경우이를 확인하는 스크립트 는 다음과 같습니다.

// Where el is the DOM element you'd like to test for visibility
function isHidden(el) {
    return (el.offsetParent === null)
}

당신이 다른 한편, 만약 않는 이 검색에 잡힐 수있는 위치에 고정 요소를 가지고, 당신은 슬프게도 (천천히) 사용해야합니다 window.getComputedStyle(). 이 경우의 기능은 다음과 같습니다.

// Where el is the DOM element you'd like to test for visibility
function isHidden(el) {
    var style = window.getComputedStyle(el);
    return (style.display === 'none')
}

옵션 # 2는 더 많은 경우를 설명하기 때문에 좀 더 간단 할 것입니다. 그러나 나는 그것도 상당히 느리게 베팅합니다. 따라서이 작업을 여러 번 반복해야한다면 피하는 것이 가장 좋습니다.


다른 모든 솔루션은 나를 위해 어떤 상황을 겪었습니다 ..

다음에서 승리하는 답변보기 :

http://plnkr.co/edit/6CSCA2fe4Gqt4jCBP2wu?p=preview

결국, 나는 최선의 해결책이라고 결정했다. $(elem).is(':visible')그러나 이것은 순수한 자바 스크립트가 아니다. jquery입니다.

그래서 나는 그들의 출처를 들여다보고 내가 원하는 것을 찾았습니다.

jQuery.expr.filters.visible = function( elem ) {
    return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
};

이것은 소스입니다 : https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js


사용자가 관심을 보인 경우 :

function isVisible(elem) {
    if (!(elem instanceof Element)) throw Error('DomUtil: elem is not an element.');
    const style = getComputedStyle(elem);
    if (style.display === 'none') return false;
    if (style.visibility !== 'visible') return false;
    if (style.opacity < 0.1) return false;
    if (elem.offsetWidth + elem.offsetHeight + elem.getBoundingClientRect().height +
        elem.getBoundingClientRect().width === 0) {
        return false;
    }
    const elemCenter   = {
        x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,
        y: elem.getBoundingClientRect().top + elem.offsetHeight / 2
    };
    if (elemCenter.x < 0) return false;
    if (elemCenter.x > (document.documentElement.clientWidth || window.innerWidth)) return false;
    if (elemCenter.y < 0) return false;
    if (elemCenter.y > (document.documentElement.clientHeight || window.innerHeight)) return false;
    let pointContainer = document.elementFromPoint(elemCenter.x, elemCenter.y);
    do {
        if (pointContainer === elem) return true;
    } while (pointContainer = pointContainer.parentNode);
    return false;
}

테스트 ( 모카 용어 사용) :

describe.only('visibility', function () {
    let div, visible, notVisible, inViewport, leftOfViewport, rightOfViewport, aboveViewport,
        belowViewport, notDisplayed, zeroOpacity, zIndex1, zIndex2;
    before(() => {
        div = document.createElement('div');
        document.querySelector('body').appendChild(div);
        div.appendChild(visible = document.createElement('div'));
        visible.style       = 'border: 1px solid black; margin: 5px; display: inline-block;';
        visible.textContent = 'visible';
        div.appendChild(inViewport = visible.cloneNode(false));
        inViewport.textContent = 'inViewport';
        div.appendChild(notDisplayed = visible.cloneNode(false));
        notDisplayed.style.display = 'none';
        notDisplayed.textContent   = 'notDisplayed';
        div.appendChild(notVisible = visible.cloneNode(false));
        notVisible.style.visibility = 'hidden';
        notVisible.textContent      = 'notVisible';
        div.appendChild(leftOfViewport = visible.cloneNode(false));
        leftOfViewport.style.position = 'absolute';
        leftOfViewport.style.right = '100000px';
        leftOfViewport.textContent = 'leftOfViewport';
        div.appendChild(rightOfViewport = leftOfViewport.cloneNode(false));
        rightOfViewport.style.right       = '0';
        rightOfViewport.style.left       = '100000px';
        rightOfViewport.textContent = 'rightOfViewport';
        div.appendChild(aboveViewport = leftOfViewport.cloneNode(false));
        aboveViewport.style.right       = '0';
        aboveViewport.style.bottom       = '100000px';
        aboveViewport.textContent = 'aboveViewport';
        div.appendChild(belowViewport = leftOfViewport.cloneNode(false));
        belowViewport.style.right       = '0';
        belowViewport.style.top       = '100000px';
        belowViewport.textContent = 'belowViewport';
        div.appendChild(zeroOpacity = visible.cloneNode(false));
        zeroOpacity.textContent   = 'zeroOpacity';
        zeroOpacity.style.opacity = '0';
        div.appendChild(zIndex1 = visible.cloneNode(false));
        zIndex1.textContent = 'zIndex1';
        zIndex1.style.position = 'absolute';
        zIndex1.style.left = zIndex1.style.top = zIndex1.style.width = zIndex1.style.height = '100px';
        zIndex1.style.zIndex = '1';
        div.appendChild(zIndex2 = zIndex1.cloneNode(false));
        zIndex2.textContent = 'zIndex2';
        zIndex2.style.left = zIndex2.style.top = '90px';
        zIndex2.style.width = zIndex2.style.height = '120px';
        zIndex2.style.backgroundColor = 'red';
        zIndex2.style.zIndex = '2';
    });
    after(() => {
        div.parentNode.removeChild(div);
    });
    it('isVisible = true', () => {
        expect(isVisible(div)).to.be.true;
        expect(isVisible(visible)).to.be.true;
        expect(isVisible(inViewport)).to.be.true;
        expect(isVisible(zIndex2)).to.be.true;
    });
    it('isVisible = false', () => {
        expect(isVisible(notDisplayed)).to.be.false;
        expect(isVisible(notVisible)).to.be.false;
        expect(isVisible(document.createElement('div'))).to.be.false;
        expect(isVisible(zIndex1)).to.be.false;
        expect(isVisible(zeroOpacity)).to.be.false;
        expect(isVisible(leftOfViewport)).to.be.false;
        expect(isVisible(rightOfViewport)).to.be.false;
        expect(isVisible(aboveViewport)).to.be.false;
        expect(isVisible(belowViewport)).to.be.false;
    });
});

도움이 될 수 있습니다 : 가장 왼쪽 위치에 배치하여 요소를 숨기고 offsetLeft 속성을 확인하십시오. jQuery를 사용하려면 : visible 선택기 를 확인 하고 요소의 가시성 상태를 얻을 수 있습니다 .

HTML :

<div id="myDiv">Hello</div>

CSS :

<!-- for javaScript-->
#myDiv{
   position:absolute;
   left : -2000px;
}

<!-- for jQuery -->
#myDiv{
    visibility:hidden;
}

자바 스크립트 :

var myStyle = document.getElementById("myDiv").offsetLeft;

if(myStyle < 0){
     alert("Div is hidden!!");
}

jQuery :

if(  $("#MyElement").is(":visible") == true )
{  
     alert("Div is hidden!!");        
}

jsFiddle


jQuery와 동일한 코드를 사용하십시오.

jQuery.expr.pseudos.visible = function( elem ) {
    return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
};

따라서 함수에서 :

function isVisible(e) {
    return !!( e.offsetWidth || e.offsetHeight || e.getClientRects().length );
}

내 Win / IE10, Linux / Firefox.45, Linux / Chrome.52의 매력처럼 작동합니다 ...

jQuery가없는 jQuery에 감사드립니다!


위의 몇 가지 답변을 결합하면 :

function isVisible (ele) {
    var style = window.getComputedStyle(ele);
    return  style.width !== "0" &&
    style.height !== "0" &&
    style.opacity !== "0" &&
    style.display!=='none' &&
    style.visibility!== 'hidden';
}

AlexZ가 말했듯이, 찾고있는 것을 더 구체적으로 알고 있다면 다른 옵션보다 느릴 수 있지만 요소가 숨겨져있는 모든 주요 방법을 포착해야합니다.

그러나 그것은 또한 당신에게 보이는 것으로 계산됩니다. 예를 들어, div의 높이는 0px로 설정할 수 있지만 넘침 속성에 따라 내용이 계속 표시됩니다. 또는 div의 내용을 배경과 같은 색으로 만들어 사용자가 볼 수는 없지만 여전히 페이지에 렌더링 할 수 있습니다. 또는 div가 화면 밖으로 이동하거나 다른 div 뒤에 숨겨 지거나 내용이 보이지 않지만 테두리가 여전히 표시 될 수 있습니다. 어느 정도 "보이는"은 주관적인 용어입니다.


요소가 정기적으로 표시되지만 (display : block 및 visibillity : visible) 일부 상위 컨테이너가 숨겨진 경우 clientWidthclientHeight사용 하여 확인할 수 있습니다.

function isVisible (ele) {
  return  ele.clientWidth !== 0 &&
    ele.clientHeight !== 0 &&
    ele.style.opacity !== 0 &&
    ele.style.visibility !== 'hidden';
}

플 런커 (여기를 클릭하십시오)


위치가 '고정 된'요소를 가질 때 AlexZ의 getComputedStyle () 솔루션과 비교하여 성능이 뛰어난 솔루션을 얻었습니다. 일부 사례를 무시하려는 경우 (주석 확인) :

function isVisible(el) {
    /* offsetParent would be null if display 'none' is set.
       However Chrome, IE and MS Edge returns offsetParent as null for elements
       with CSS position 'fixed'. So check whether the dimensions are zero.

       This check would be inaccurate if position is 'fixed' AND dimensions were
       intentionally set to zero. But..it is good enough for most cases.*/
    if (!el.offsetParent && el.offsetWidth === 0 && el.offsetHeight === 0) {
        return false;
    }
    return true;
}

참고 : 엄밀히 말하면 "가시성"을 먼저 정의해야합니다. 내 경우에는 불투명도가 0이거나 CSS 가시성 속성이 '숨겨진'등에도 문제없이 모든 DOM 메소드 / 속성을 실행할 수있는 한 요소를 볼 수 있습니다.


가시성을 감지하는 기본 방법을 수집하는 경우 다음을 잊지 마십시오.

opacity > 0.01; // probably more like .1 to actually be visible, but YMMV

그리고 속성을 얻는 방법에 관해서 :

element.getAttribute(attributename);

따라서 귀하의 예에서 :

document.getElementById('snDealsPanel').getAttribute('visibility');

하지만 뭐? 여기서 작동하지 않습니다. 자세히 살펴보면 가시성이 요소의 style속성이 아니라 속성을 사용하여 업데이트되고 있음을 알 수 있습니다. 이것은 당신이하고있는 일을하려고하는 데 많은 문제 중 하나입니다. 무엇보다도, 가시성, 표시 및 불투명도가 모두 올바른 값을 가지고 있기 때문에 실제로 요소에 볼 것이 있다는 것을 보장 할 수 없습니다. 여전히 내용이 없거나 높이와 너비가 부족할 수 있습니다. 다른 물체로 인해 모호해질 수 있습니다. 자세한 내용은 빠른 Google 검색에서 이를 표시 하고 문제를 해결하기위한 라이브러리도 포함합니다. (YMMV)

강력한 John Resig의 통찰력을 포함하여 훌륭한 답변 으로이 질문과 중복되는 다음 내용을 확인하십시오. 그러나 특정 사용 사례는 표준 사용 사례와 약간 다르므로 플래그 지정을 삼가겠습니다.

(편집 : OP는 페이지를 지우고 페이지를 작성하지 않으므로 해당 사항이 적용되지 않습니다) 더 나은 옵션은 무엇입니까? Angular가 ng-show를 사용하는 것처럼 요소의 가시성을 모델 속성에 바인딩하고 항상 해당 모델에 가시성을 부여합니다. 원하는 도구를 사용하여 수행 할 수 있습니다 : 각도, 일반 JS 등 무엇이든. 더 좋은 점은 시간이 지남에 따라 DOM 구현을 변경할 수 있지만 DOM 대신 항상 모델에서 상태를 읽을 수 있다는 것입니다. DOM에서 진실을 읽는 것은 나쁘다. 그리고 천천히. 모델을 확인하고 DOM 상태가 모델을 반영하도록 구현을 신뢰하는 것이 훨씬 좋습니다. 그리고 자동 테스트를 사용하여 해당 가정을 확인하십시오.


그래서 내가 찾은 것은 가장 가능한 방법입니다.

function visible(elm) {
  if(!elm.offsetHeight && !elm.offsetWidth) { return false; }
  if(getComputedStyle(elm).visibility === 'hidden') { return false; }
  return true;
}

이것은 다음과 같은 사실을 바탕으로합니다.

  • display: none요소 (심지어 중첩 된 하나) 폭이나 높이를 가지고 있지 않습니다.
  • visiblity이다 hidden도 중첩 된 요소.

따라서 offsetParent어떤 부모가 있는지 테스트하기 위해 DOM 트리에서 테스트 하거나 루핑 할 필요가 없습니다 visibility: hidden. 이것은 IE 9에서도 작동합니다.

opacity: 0너비와 높이가없는 요소와 축소 된 요소가 실제로 보이지 않는 경우 논쟁 할 수 있습니다. 그러나 다시 말하지만 그들은 숨겨져 있지 않습니다.


ohad navon의 답변에 약간의 추가.

요소의 중심이 다른 요소에 속하면 찾을 수 없습니다.

따라서 요소의 점 중 하나가 보이는지 확인하려면

function isElementVisible(elem) {
    if (!(elem instanceof Element)) throw Error('DomUtil: elem is not an element.');
    const style = getComputedStyle(elem);
    if (style.display === 'none') return false;
    if (style.visibility !== 'visible') return false;
    if (style.opacity === 0) return false;
    if (elem.offsetWidth + elem.offsetHeight + elem.getBoundingClientRect().height +
        elem.getBoundingClientRect().width === 0) {
        return false;
    }
    var elementPoints = {
        'center': {
            x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,
            y: elem.getBoundingClientRect().top + elem.offsetHeight / 2
        },
        'top-left': {
            x: elem.getBoundingClientRect().left,
            y: elem.getBoundingClientRect().top
        },
        'top-right': {
            x: elem.getBoundingClientRect().right,
            y: elem.getBoundingClientRect().top
        },
        'bottom-left': {
            x: elem.getBoundingClientRect().left,
            y: elem.getBoundingClientRect().bottom
        },
        'bottom-right': {
            x: elem.getBoundingClientRect().right,
            y: elem.getBoundingClientRect().bottom
        }
    }

    for(index in elementPoints) {
        var point = elementPoints[index];
        if (point.x < 0) return false;
        if (point.x > (document.documentElement.clientWidth || window.innerWidth)) return false;
        if (point.y < 0) return false;
        if (point.y > (document.documentElement.clientHeight || window.innerHeight)) return false;
        let pointContainer = document.elementFromPoint(point.x, point.y);
        if (pointContainer !== null) {
            do {
                if (pointContainer === elem) return true;
            } while (pointContainer = pointContainer.parentNode);
        }
    }
    return false;
}

http://code.jquery.com/jquery-1.11.1.js 의 jQuery 코드 에는 isHidden 매개 변수가 있습니다.

var isHidden = function( elem, el ) {
    // isHidden might be called from jQuery#filter function;
    // in that case, element will be second argument
    elem = el || elem;
    return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
};

소유자 문서와 관련된 추가 검사가있는 것 같습니다.

이것이 실제로 다음과 같은 경우에 해당하는지 궁금합니다.

  1. zIndex를 기반으로 다른 요소 뒤에 숨겨진 요소
  2. 투명성을 가진 요소는 보이지 않게 만듭니다.
  3. 화면 외부에 배치 된 요소 (예 : 왼쪽 : -1000px)
  4. 가시성이있는 요소 : 숨김
  5. 디스플레이가있는 요소 : 없음
  6. 보이는 텍스트 나 하위 요소가없는 요소
  7. 높이 또는 너비가 0으로 설정된 요소

참고 getBoundingClientRect()로 특정 경우에는 작동 할 수 있습니다.

예를 들어, 요소가 숨겨져 있는지 확인하는 간단한 방법 display: none은 다음과 같습니다.

var box = element.getBoundingClientRect();
var visible = box.width && box.height;

너비가 0, 높이가 0 및 position: fixed사례 도 포함하므로 편리합니다 . 그러나 opacity: 0또는로 숨겨진 요소는보고하지 않아야합니다 visibility: hidden(그러나 둘 다 offsetParent).


의 @Guy Messika의 대답을 개선 하고 중심 점 'X가 0보다 작 으면 false를 반환하고 반환하면 요소 오른쪽이 뷰에 들어갈 수 있습니다. 다음은 수정 사항입니다.

private isVisible(elem) {
    const style = getComputedStyle(elem);

    if (style.display === 'none') return false;
    if (style.visibility !== 'visible') return false;
    if ((style.opacity as any) === 0) return false;

    if (
        elem.offsetWidth +
        elem.offsetHeight +
        elem.getBoundingClientRect().height +
        elem.getBoundingClientRect().width === 0
    ) return false;

    const elementPoints = {
        center: {
            x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,
            y: elem.getBoundingClientRect().top + elem.offsetHeight / 2,
        },
        topLeft: {
            x: elem.getBoundingClientRect().left,
            y: elem.getBoundingClientRect().top,
        },
        topRight: {
            x: elem.getBoundingClientRect().right,
            y: elem.getBoundingClientRect().top,
        },
        bottomLeft: {
            x: elem.getBoundingClientRect().left,
            y: elem.getBoundingClientRect().bottom,
        },
        bottomRight: {
            x: elem.getBoundingClientRect().right,
            y: elem.getBoundingClientRect().bottom,
        },
    };

    const docWidth = document.documentElement.clientWidth || window.innerWidth;
    const docHeight = document.documentElement.clientHeight || window.innerHeight;

    if (elementPoints.topLeft.x > docWidth) return false;
    if (elementPoints.topLeft.y > docHeight) return false;
    if (elementPoints.bottomRight.x < 0) return false;
    if (elementPoints.bottomRight.y < 0) return false;

    for (let index in elementPoints) {
        const point = elementPoints[index];
        let pointContainer = document.elementFromPoint(point.x, point.y);
        if (pointContainer !== null) {
            do {
                if (pointContainer === elem) return true;
            } while (pointContainer = pointContainer.parentNode);
        }
    }
    return false;
}

이것은 요소와 모든 조상이 보이는 경우에만 true를 반환합니다. displayand visibility스타일 속성 만 살펴 봅니다 .

    var isVisible = function(el){
        // returns true iff el and all its ancestors are visible
        return el.style.display !== 'none' && el.style.visibility !== 'hidden'
        && (el.parentElement? isVisible(el.parentElement): true)
    };

다음은 몇 가지 유사한 요소 중 하나만 표시하고 jQuery없이 "class"속성의 값을 반환하기 위해 작성한 코드입니다.

  // Build a NodeList:
  var nl = document.querySelectorAll('.myCssSelector');

  // convert it to array:
  var myArray = [];for(var i = nl.length; i--; myArray.unshift(nl[i]));

  // now find the visible (= with offsetWidth more than 0) item:
  for (i =0; i < myArray.length; i++){
    var curEl = myArray[i];
    if (curEl.offsetWidth !== 0){
      return curEl.getAttribute("class");
    }
  }

이것이 내가 한 일입니다.

HTML 및 CSS : 기본적으로 요소를 숨겼습니다.

<html>
<body>

<button onclick="myFunction()">Click Me</button>

<p id="demo" style ="visibility: hidden;">Hello World</p> 

</body>
</html> 

JavaScript : 가시성이 숨겨져 있는지 여부를 확인하는 코드가 추가되었습니다.

<script>
function myFunction() {
   if ( document.getElementById("demo").style.visibility === "hidden"){
   document.getElementById("demo").style.visibility = "visible";
   }
   else document.getElementById("demo").style.visibility = "hidden";
}
</script>

이것은 가시성을 포함하여 모든 CSS 속성에 대해 결정하는 방법입니다.

html :

<div id="element">div content</div>

CSS :

#element
{
visibility:hidden;
}

자바 스크립트 :

var element = document.getElementById('element');
 if(element.style.visibility == 'hidden'){
alert('hidden');
}
else
{
alert('visible');
}

그것은 모든 CSS 속성에서 작동하며 매우 다양하고 신뢰할 수 있습니다.

참고 URL : https://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom



반응형