有什么方法,我可以检查如果一个元素是可见的纯JS(没有jQuery) ?
因此,给定一个DOM元素,我如何检查它是否可见?我试着:
window.getComputedStyle(my_element)['display']);
但这似乎并不奏效。我想知道我应该检查哪些属性。我想到了:
display !== 'none'
visibility !== 'hidden'
还有我可能漏掉的吗?
有什么方法,我可以检查如果一个元素是可见的纯JS(没有jQuery) ?
因此,给定一个DOM元素,我如何检查它是否可见?我试着:
window.getComputedStyle(my_element)['display']);
但这似乎并不奏效。我想知道我应该检查哪些属性。我想到了:
display !== 'none'
visibility !== 'hidden'
还有我可能漏掉的吗?
当前回答
所以我找到了最可行的方法:
function visible(elm) {
if(!elm.offsetHeight && !elm.offsetWidth) { return false; }
if(getComputedStyle(elm).visibility === 'hidden') { return false; }
return true;
}
这是基于以下事实:
显示:所有元素(即使是嵌套的元素)都没有宽度和高度。 可见性即使对于嵌套的元素也是隐藏的。
因此不需要测试offsetParent或在DOM树中循环来测试哪个父对象具有可见性:hidden。这应该可以在ie9中工作。
你可能会说,如果透明度:0和折叠的元素(有宽度但没有高度-反之亦然)也不是真正可见的。但话说回来,它们并不是隐藏的。
其他回答
如果你正在抓取网站,一个非常低效的方法对我来说是突出显示任何元素,然后截图,然后检查截图是否发生了变化。
//Screenshot
function makeSelected(element){
let range = new Range()
range.selectNode(element)
let selection = window.getSelection()
selection.removeAllRanges()
selection.addRange(range)
}
// screenshot again and check for diff
仅供参考,应该注意getBoundingClientRect()在某些情况下可以工作。
例如,使用display: none简单检查元素是否被隐藏,可能看起来像这样:
var box = element.getBoundingClientRect();
var visible = box.width && box.height;
这也很方便,因为它还涵盖了零宽度、零高度和位置:固定的情况。但是,它不应该报告使用opacity: 0或visibility: hidden隐藏的元素(但是也不会报告offsetParent)。
const isVisible = (selector) => { let selectedElement let topElement let selectedData selectedElement = document.querySelector(selector) if (!selectedElement) { return false } selectedData = selectedElement.getBoundingClientRect() if (!selectedData || !Object.keys(selectedData)) { return false } if (!(selectedData.width > 0) || !(selectedData.height > 0)) { return false } topElement = document.elementFromPoint(selectedData.top, selectedData.left) if (selectedElement !== topElement) { return false } return true } const output = document.querySelector('.text') output.innerHTML = '.x element is visible: ' + isVisible('.x') .block { width: 100px; height: 100px; background: black; } .y { background: red; margin-top: -100px; } <div class="text"></div> <div class="x block"></div> <div class="y block"></div>
let element = document.getElementById('element');
let rect = element.getBoundingClientRect();
if(rect.top == 0 &&
rect.bottom == 0 &&
rect.left == 0 &&
rect.right == 0 &&
rect.width == 0 &&
rect.height == 0 &&
rect.x == 0 &&
rect.y == 0)
{
alert('hidden');
}
else
{
alert('visible');
}
如果你对用户可见感兴趣:
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;
});
});