ตรวจสอบว่าองค์ประกอบสามารถมองเห็นได้ใน DOM


377

มีวิธีใดบ้างที่ฉันสามารถตรวจสอบว่าองค์ประกอบมองเห็นได้ใน JS บริสุทธิ์ (ไม่มี jQuery)?

ตัวอย่างเช่นในหน้านี้: จักรยานประสิทธิภาพถ้าคุณวางเมาส์เหนือดีล (บนเมนูด้านบน) จะมีหน้าต่างของดีลปรากฏขึ้น แต่ในตอนแรกมันจะไม่แสดง มันอยู่ใน HTML แต่มองไม่เห็น

ดังนั้นเมื่อกำหนดองค์ประกอบ DOM ฉันจะตรวจสอบว่าสามารถมองเห็นได้หรือไม่ ฉันเหนื่อย:

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

แต่ดูเหมือนจะไม่ทำงาน ฉันสงสัยว่าฉันควรตรวจสอบคุณลักษณะใด มันอยู่ในใจของฉัน:

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

คนอื่นที่ฉันอาจหายไป?


1
ที่ไม่ได้ใช้จอแสดงผลมันใช้การมองเห็นดังนั้นตรวจสอบการมองเห็น (ซ่อนหรือมองเห็นได้) เช่น:document.getElementById('snDealsPanel').style.visibility
PSL

PSL หากฉันต้องการทำสิ่งนี้ให้ทั่วๆไปฉันควรตรวจสอบคุณลักษณะใด: การมองเห็นการแสดงผล ...
Hommer Smith

คุณสามารถทำให้เป็นเรื่องทั่วไปในแบบของคุณเอง แต่สิ่งที่ฉันพูดคือใช้การมองเห็นการตรวจสอบองค์ประกอบ
PSL

นี่คือรหัสของฉัน (ไม่มี jquery) สำหรับคำถามนี้stackoverflow.com/a/22969337/2274995
Aleko

ลิงก์เสียซึ่งทำให้คำถามของคุณไม่เข้าใจง่าย กรุณาจัดเฟรมใหม่
yogihosting

คำตอบ:


617

ตามเอกสาร MDN นี้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 อาจจะตรงไปตรงมามากกว่าเล็กน้อยเนื่องจากมันเป็นคดีขอบที่มากขึ้น แต่ฉันพนันได้ว่ามันจะช้าลงเช่นกันดังนั้นหากคุณต้องทำซ้ำการดำเนินการนี้หลายครั้งควรหลีกเลี่ยง


ว้าวไม่มีล้อเล่น Imo ไม่ควรมีเหตุผลที่จะใช้วิธีที่สองเป็นวิธีแก้ปัญหาสากล หน้าไม่ควรมีองค์ประกอบคงที่ที่ผู้สร้างไม่ทราบอย่างชัดเจนและหนึ่งสามารถตรวจสอบด้วยตนเองโดยใช้วิธี getComputedStyle () หลังจากใช้วิธีการ offsetParent ในองค์ประกอบทั้งหมดก่อน
AlexZ

6
นอกจากนี้ FYI เพิ่งค้นพบel.offsetParentว่าไม่ได้ทำงานบน IE9 สำหรับองค์ประกอบที่ไม่คงที่ หรือดังนั้นดูเหมือนว่า (ตกลงสำหรับ IE11) ดังนั้นไปด้วยgetComputedStyleกัน
Nick

1
@AlexZ ฉันไม่แน่ใจว่า offsetParent ทำการ reflow ในเบราว์เซอร์ของวันนี้จริง ๆ หรือไม่ แต่ใช่สองสามปีก่อนพวกเขาคุ้นเคยนั่นคือสิ่งที่ฉันเข้าใจจากรายงาน โปรดทราบว่า jsPerf กล่าวถึงความเร็วของการดำเนินการเท่านั้นในขณะที่ reflow นั้นเกี่ยวกับจอแสดงผล และการ reflow ทำให้ UI แย่ลง โดยส่วนตัวฉันจะไม่ไปที่ความเร็วสำหรับรูทีนที่อาจเรียกว่า 5/6 ครั้งบนหน้าเว็บ
Ethan

2
อนิจจา! getComputedStyleทำงานไม่ถูกต้อง: plnkr.co/edit/6CSCA2fe4Gqt4jCBP2wu?p=previewอย่างไรก็ตามเช่นนั้นoffsetParent- อาจใช้ทั้งสองอย่างร่วมกันหรือไม่
guy mograbi

2
สำหรับ ie9 + ie10 คุณสามารถตรวจสอบว่า offsetParent = body สำหรับองค์ประกอบที่มองไม่เห็น
SuperUberDuper

99

โซลูชันอื่นทั้งหมดแตกสำหรับบางสถานการณ์สำหรับฉัน ..

ดูคำตอบที่ชนะได้ที่:

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


11
สิ่งนี้จะส่งคืนtrueสำหรับองค์ประกอบที่มีvisibility:hidden
Yuval A.

9
@YuvalA: ใช่เพราะองค์ประกอบยังคงมองเห็นได้ การตั้งค่าองค์ประกอบvisibility:hiddenให้ไม่แสดงเนื้อหาอีกต่อไป แต่ยังต้องใช้ความกว้างและความสูงขององค์ประกอบ!
Jacob van Lingen

4
@Michael คุณสามารถเรียกดูรหัส jQuery ได้อย่างง่ายดายและหากคุณใช้ IDE ที่ทันสมัย ​​(ลองใช้ถ้าไม่ใช่) คุณสามารถข้ามไปแก้ไขส่วนรหัสได้ในขณะที่ใช้ jQuery หรือ lib อื่น ๆ คุณสามารถเรียนรู้ได้มากมายในขณะที่กำลังอ่านโค๊ตฐานของโครงการโอเพ่นซอร์ส
Lukas Liesis

53

หากคุณสนใจให้ผู้ใช้มองเห็น:

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

เคสแบบขอบหากตำแหน่ง elem อยู่นอกวิวพอร์ตสามารถจับได้โดย "if (! pointContainer) return false" กำลังตรวจสอบจุดแรกผู้ให้บริการ
Jerry Deng

หากคุณต้องการตรวจสอบว่าผู้ใช้สามารถเห็นได้หรือไม่คุณต้องใช้scrollIntoViewใช่มั้ย! อันนี้ค่อนข้างแพง มีวิธีที่ฉลาดกว่านี้ไหม?
Kim Kern

36

สิ่งนี้อาจช่วยได้: ซ่อนองค์ประกอบโดยการวางตำแหน่งไว้ที่ตำแหน่งซ้ายสุดสุดจากนั้นตรวจสอบคุณสมบัติ offsetLeft หากคุณต้องการใช้ jQuery คุณสามารถตรวจสอบตัวเลือกที่มองเห็นได้และรับสถานะการมองเห็นขององค์ประกอบ

HTML:

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

CSS:

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

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

javaScript:

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

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

jQuery:

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

jsFiddle


12
OP ขอคำตอบที่ไม่ใช่ jQuery
Stephen Quan

มันถูกแก้ไขในภายหลังฉันเดา เมื่อฉันตอบมันไม่ได้กล่าวถึงในหัวข้อ
Md. Ashaduzzaman

2
@StephenQuan ฉันได้อัปเดตคำตอบด้วยโซลูชัน jQuery และ javaScript แล้ว
Md. Ashaduzzaman

6
สำหรับตัวอย่าง jQuery ไม่ควรมีข้อความแจ้งเตือนว่า "Div มองเห็นได้"
Andrei Bazanov

ฉันไม่ต้องการที่จะสรุปองค์ประกอบที่ถูกซ่อนทั้งหมดเพียงเพราะ offsetLeft น้อยกว่า 0: จะเป็นอย่างไรถ้ามีจำนวนพิกเซลน้อยกว่า 0 เพียงเล็กน้อยและมองเห็นส่วนด้านขวามือ (ฉันเห็นด้วยกับสิ่งนี้ดูเหมือนว่าจะเป็นการออกแบบที่โง่ แต่คุณไม่เคยรู้จักกับนักออกแบบเว็บไซต์มาก่อน) ควรเพิ่มความกว้างให้ออฟเซ็ตซ้ายและดูว่าผลลัพธ์ยังน้อยกว่า 0 ในกรณีนี้หรือไม่
Silas S. Brown

31

ใช้รหัสเดียวกันกับ 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!


ดี แต่ไม่ครอบคลุมองค์ประกอบที่ถูกซ่อนไว้โดยการล้น
Alph.Dev

ดี แต่ทำไม !! (ปฏิเสธคู่)
นิล Garg

3
เพื่อบังคับให้ผลเป็นบูลีน ในฐานะที่e.offsetWidthเป็นจำนวนเต็ม!e.offsetWidthจะกลับfalseถ้าe.offsetWidthสูงกว่าศูนย์ (องค์ประกอบที่มองเห็นได้) ดังนั้นการเพิ่มอีก!อย่างใน!!e.offsetWidthจะกลับมาtrueถ้าe.offsetWidthสูงกว่าศูนย์ มันเป็นชวเลขสำหรับหรืออย่างเห็นได้ชัดreturn e.offsetWidth > 0 ? true : false return e.offsetWidth > 0
Yvan

16

รวมคำตอบสองสามข้อด้านบน:

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 สามารถทำให้มีสีเดียวกับพื้นหลังดังนั้นผู้ใช้จะมองไม่เห็น แต่ยังแสดงผลบนหน้าเว็บ หรือกองอาจถูกย้ายออกจากหน้าจอหรือซ่อนอยู่ด้านหลังกองอื่นหรือเนื้อหาของมันอาจไม่สามารถมองเห็นได้ แต่เส้นขอบยังคงมองเห็นได้ ในระดับหนึ่ง "มองเห็นได้" เป็นคำที่เป็นอัตวิสัย


1
ดี แต่ style.opacity, style.height และ style.width ส่งคืนสตริงดังนั้นมันจะไม่ทำงานด้วย! ==
Maslow

อีกวิธีหนึ่งที่องค์ประกอบอาจถูกซ่อนไว้ผ่านสไตล์คือสีของมันอาจตรงกับสีพื้นหลังหรือดัชนี z อาจต่ำกว่าองค์ประกอบอื่น ๆ
nu everest

เพิ่มdisplay:noneไปนี้จะดี ทางออกการทำงานที่เหมาะสม!
Gijo Varghese

7

ฉันมีวิธีแก้ปัญหาที่มีประสิทธิภาพมากกว่าเมื่อเปรียบเทียบกับโซลูชัน getComputedStyle () ของ AlexZเมื่อมีองค์ประกอบตำแหน่ง 'คงที่' ถ้ามีใครยอมเพิกเฉยกรณีขอบ (ตรวจสอบความคิดเห็น):

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

หมายเหตุด้านข้าง: การพูดอย่างเคร่งครัดจำเป็นต้องกำหนด "การมองเห็น" ก่อน ในกรณีของฉันฉันกำลังพิจารณาองค์ประกอบที่สามารถมองเห็นได้ตราบใดที่ฉันสามารถเรียกใช้วิธีการ / คุณสมบัติ DOM ทั้งหมดโดยไม่มีปัญหา (แม้ว่าความทึบเป็น 0 หรือคุณสมบัติการมองเห็น CSS เป็น 'ซ่อน' ฯลฯ )


6

หากองค์ประกอบเป็นปกติที่มองเห็นได้ (display: block และ visibillity: visible) แต่คอนเทนเนอร์หลักบางส่วนถูกซ่อนไว้เราสามารถใช้clientWidthและclientHeightเพื่อตรวจสอบว่า

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

พลั่วเกอร์ (คลิกที่นี่)


ele.style.visibility !== 'hidden'ซ้ำซ้อนที่นี่ ในกรณีดังกล่าว clientWidth และ clientHeight จะเป็น 0
subdavis

5

หากเราเพียงรวบรวมวิธีพื้นฐานในการตรวจจับการมองเห็นให้ฉันอย่าลืม:

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 คุณสามารถทำได้โดยใช้เครื่องมือใด ๆ ที่คุณต้องการ: Angular, JS ธรรมดา ๆ ยังดีกว่าคุณสามารถเปลี่ยนการใช้งาน DOM เมื่อเวลาผ่านไป แต่คุณจะสามารถอ่านสถานะจากโมเดลได้เสมอแทนที่จะเป็น DOM การอ่านความจริงของคุณจาก DOM นั้นแย่ และช้า ดีกว่ามากในการตรวจสอบรูปแบบและเชื่อมั่นในการใช้งานของคุณเพื่อให้แน่ใจว่าสถานะ DOM สะท้อนให้เห็นถึงรูปแบบ (และใช้การทดสอบอัตโนมัติเพื่อยืนยันสมมติฐานนั้น)


ฉันกำลังทำการแยกวิเคราะห์ไซต์นี่ไม่ใช่สำหรับเว็บไซต์ของฉันเอง ... :)
Hommer Smith

4

คำตอบที่ยอมรับไม่ได้ผลสำหรับฉัน ตอบปี 2563 :

1) วิธีการ(elem.offsetParent! == null)ทำงานได้ดีใน Firefox แต่ไม่ใช่ใน Chrome สำหรับตำแหน่ง "Chrome: fixed;" จะทำให้ offsetParent return "null" แม้องค์ประกอบหากมองเห็นได้ในหน้า

การสาธิต:

//different results in Chrome and Firefox
console.log(document.querySelector('#hidden1').offsetParent); //null Chrome & Firefox
console.log(document.querySelector('#fixed1').offsetParent); //null in Chrome, not null in Firefox
    <div id="hidden1" style="display:none;"></div>
    <div id="fixed1" style="position:fixed;"></div>

คุณสามารถเห็นผู้ชายคนนี้ megatest https://stackoverflow.com/a/11639664/4481831 (เรียกใช้ด้วยเบราว์เซอร์หลายตัวเพื่อดูความแตกต่าง)

2) (getComputedStyle (elem) .display! == 'none')ไม่ทำงานเนื่องจากองค์ประกอบสามารถมองไม่เห็นเพราะหนึ่งในผู้ปกครองแสดงคุณสมบัติการตั้งค่าเป็น none, getComputedStyle จะไม่จับที่

การสาธิต:

var child1 = document.querySelector('#child1');
console.log(getComputedStyle(child1).display);
//child will show "block" instead of "none"
<div id="parent1" style="display:none;">
  <div id="child1" style="display:block"></div>
</div>

3) (elem.clientHeight! == 0) วิธีนี้ไม่ได้รับอิทธิพลจากตำแหน่งที่คงที่และยังตรวจสอบว่าผู้ปกครององค์ประกอบไม่สามารถมองเห็นได้ แต่มันมีปัญหากับองค์ประกอบง่าย ๆ ที่ไม่มีเค้าโครง css ดูเพิ่มเติมที่นี่

การสาธิต:

console.log(document.querySelector('#div1').clientHeight); //not zero
console.log(document.querySelector('#span1').clientHeight); //zero
<div id="div1">test1 div</div>
<span id="span1">test2 span</span>

4) The (elem.getClientRects (). length! == 0)ที่ดูเหมือนจะข้ามปัญหาของ 3 วิธีก่อนหน้านี้ อย่างไรก็ตามมีปัญหาเกี่ยวกับองค์ประกอบที่ใช้เทคนิค CSS (อื่น ๆ แล้ว "display: none") เพื่อซ่อนในหน้า

console.log(document.querySelector('#notvisible1').getClientRects().length);
console.log(document.querySelector('#notvisible1').clientHeight);
console.log(document.querySelector('#notvisible2').getClientRects().length);
console.log(document.querySelector('#notvisible2').clientHeight);
console.log(document.querySelector('#notvisible3').getClientRects().length);
console.log(document.querySelector('#notvisible3').clientHeight);
<div id="notvisible1" style="height:0; overflow:hidden; background-color:red;">not visible 1</div>

<div id="notvisible2" style="visibility:hidden; background-color:yellow;">not visible 2</div>

<div id="notvisible3" style="opacity:0; background-color:blue;">not visible 3</div>

สรุป: สิ่งที่ฉันได้แสดงให้คุณเห็นก็คือไม่มีวิธีใดที่สมบูรณ์แบบ ในการตรวจสอบการมองเห็นที่ถูกต้องคุณต้องใช้วิธีการทั้ง 3 วิธีร่วมกัน


3

เพียงเพื่อการอ้างอิงควรสังเกตว่าgetBoundingClientRect()สามารถทำงานได้ในบางกรณี

ตัวอย่างเช่นการตรวจสอบง่าย ๆ ว่าองค์ประกอบที่ถูกซ่อนใช้display: noneอาจมีลักษณะเช่นนี้:

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

นอกจากนี้ยังเป็นประโยชน์เพราะมันยังครอบคลุมถึงการเป็นศูนย์ที่มีความกว้างเป็นศูนย์ที่มีความสูงและposition: fixedกรณี อย่างไรก็ตามจะไม่รายงานองค์ประกอบที่ซ่อนอยู่ด้วยopacity: 0หรือvisibility: hidden(แต่จะไม่มีoffsetParent)


คำตอบที่ดีที่สุดสำหรับฉัน ... เรียบง่ายและมีประสิทธิภาพ และไม่มีโหวตเดียวหลังจาก 3 ปี! ยังคงแสดงให้เห็นถึงคุณค่าของ "ภูมิปัญญาของฝูงชน" รุ่นของฉัน: var isVisible = el => (r => r.width && r.height)(el.getBoundingClientRect());. จากนั้นฉันสามารถกรองอาร์เรย์ขององค์ประกอบด้วยวิธีต่อไปนี้: $$(sel).filter(isVisible).
7vujy0f0hy

ฉันพบว่ามันเป็นทางออกที่ง่ายที่สุดdeveloper.mozilla.org/en-US/docs/Web/API/Element/
......

สิ่งนี้จะไม่ทำงานเมื่อผู้ใช้มองเห็น ... หากคุณเลื่อนออกไปมันจะยังคงเป็นจริง
Ray Foss

3

ดังนั้นสิ่งที่ฉันพบคือวิธีที่เป็นไปได้มากที่สุด:

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องค์ประกอบที่ยุบตัว (มีความกว้าง แต่ไม่มีส่วนสูง - หรือในทางกลับกัน) ก็ไม่สามารถมองเห็นได้เช่นกัน แต่แล้วอีกครั้งพวกเขาจะไม่พูดต่อซ่อน


3

นอกจากนี้เล็กน้อยเพื่อคำตอบของ 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;
}

3

การปรับปรุงคำตอบของ @Guy Messika ด้านบนให้ทำลายและส่งคืนค่าเท็จหากจุดศูนย์กลาง 'X คือ <0 ผิดเนื่องจากองค์ประกอบด้านขวาอาจเข้าสู่มุมมอง นี่คือการแก้ไข:

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

2

รหัส jQuery จากhttp://code.jquery.com/jquery-1.11.1.jsมีพารามิเตอร์แบบซ่อนอยู่

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

0

นี่คือโค้ดที่ฉันเขียนเพื่อค้นหาสิ่งที่มองเห็นได้จากองค์ประกอบที่คล้ายกันสองสามอย่างและคืนค่าของแอตทริบิวต์ "class" โดยไม่ต้อง jQuery:

  // 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");
    }
  }

0

นี่คือสิ่งที่ฉันทำ:

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>

-1

นี่เป็นวิธีการตรวจสอบสำหรับคุณสมบัติ css ทั้งหมดรวมถึงการมองเห็น:

HTML:

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

CSS:

#element
{
visibility:hidden;
}

javascript:

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

มันใช้งานได้กับคุณสมบัติ CSS ใด ๆ และมีความหลากหลายและน่าเชื่อถือ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.