有什么方法,我可以检查如果一个元素是可见的纯JS(没有jQuery) ?
因此,给定一个DOM元素,我如何检查它是否可见?我试着:
window.getComputedStyle(my_element)['display']);
但这似乎并不奏效。我想知道我应该检查哪些属性。我想到了:
display !== 'none'
visibility !== 'hidden'
还有我可能漏掉的吗?
有什么方法,我可以检查如果一个元素是可见的纯JS(没有jQuery) ?
因此,给定一个DOM元素,我如何检查它是否可见?我试着:
window.getComputedStyle(my_element)['display']);
但这似乎并不奏效。我想知道我应该检查哪些属性。我想到了:
display !== 'none'
visibility !== 'hidden'
还有我可能漏掉的吗?
当前回答
如果你正在抓取网站,一个非常低效的方法对我来说是突出显示任何元素,然后截图,然后检查截图是否发生了变化。
//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
其他回答
有许多情况下,这将不一定工作,但在我的情况下,我正在使用这个,它为我所需要的工作。所以,如果你正在寻找一个基本的解决方案(不包括所有的可能性),如果这个简单的解决方案适合你的特殊需求,它“可能”对你有帮助。
var element= document.getElementById('elementId');
if (element.style.display == "block"){
<!-- element is visible -->
} else {
<!-- element is hidden-->
}
下面是一个(纯纯的JS)函数,它执行大量的检查,确保给定的元素对用户可见:
function isVisible(element) {
// Check if the element is null or undefined
if (!element) return false;
// Get the element's bounding client rect
const boundingRect = element.getBoundingClientRect();
// Check if the element has a positive width and height
if (boundingRect.width <= 0 || boundingRect.height <= 0) return false;
// Check if the element's top and left values are within the viewport
const top = boundingRect.top;
const left = boundingRect.left;
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
if (top > viewportHeight || left > viewportWidth) return false;
// Check if the element's right and bottom values are within the viewport
const right = boundingRect.right;
const bottom = boundingRect.bottom;
if (right < 0 || bottom < 0) return false;
// Check if the element is hidden by the overflow property
const parentNode = element.parentNode;
if (parentNode && getComputedStyle(parentNode).overflow === 'hidden') {
const parentRect = parentNode.getBoundingClientRect();
if (top < parentRect.top || bottom > parentRect.bottom || left < parentRect.left || right > parentRect.right) {
return false;
}
}
const elementComputedStyle = getComputedStyle(element);
// Check if the element has a z-index of less than 0
const zIndex = elementComputedStyle.zIndex;
if (zIndex < 0) return false;
// Check if the element has a display value of 'none' or an opacity of 0
const display = elementComputedStyle.display;
const opacity = elementComputedStyle.opacity;
if (display === 'none' || opacity === '0') return false;
// Check if the element is hidden by an ancestor element with a display value of 'none' or an opacity of 0
let ancestorElement = element.parentElement;
while (ancestorElement) {
const ancestorComputedStyle = getComputedStyle(ancestorElement);
const ancestorDisplay = ancestorComputedStyle.display;
const ancestorOpacity = ancestorComputedStyle.opacity;
if (ancestorDisplay === 'none' || ancestorOpacity === '0') return false;
ancestorElement = ancestorElement.parentElement;
}
// Initialize a variable to keep track of whether the element is obscured by another element
let obscured = false;
// Check if the element is obscured by another element according to its position
if (elementComputedStyle.position === 'absolute' || elementComputedStyle.position === 'fixed' ||
elementComputedStyle.position === 'relative' || elementComputedStyle.position === 'sticky' ||
elementComputedStyle.position === 'static') {
let siblingElement = element.nextElementSibling;
while (siblingElement) {
if (siblingElement.getBoundingClientRect().top > boundingRect.bottom || siblingElement.getBoundingClientRect().left > boundingRect.right) {
break;
}
if (siblingElement.getBoundingClientRect().bottom > boundingRect.top && siblingElement.getBoundingClientRect().right > boundingRect.left) {
obscured = true;
break;
}
siblingElement = siblingElement.nextElementSibling;
}
if (obscured) return false;
}
// If all checks have passed, the element is visible
return true;
}
改进了上面@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;
}
2021的解决方案
根据MDN文档,交互观察器异步观察目标元素与祖先元素或顶级文档视口的交集中的变化。这意味着每当元素与视口相交时,交互观察器就会触发。
截至2021年,除IE外,目前所有浏览器都支持交集观测器。
实现
const el = document.getElementById("your-target-element");
const observer = new IntersectionObserver((entries) => {
if(entries[0].isIntersecting){
// el is visible
} else {
// el is not visible
}
});
observer.observe(el); // Asynchronous call
The handler will fire when initially created. And then it will fire every time that it becomes slightly visible or becomes completely not visible. An element is deemed to be not-visible when it's not actually visible within the viewport. So if you scroll down and element goes off the screen, then the observer will trigger and the // el is not visible code will be triggered - even though the element is still "displayed" (i.e. doesn't have display:none or visibility:hidden). What matters is whether there are any pixels of the element that are actually visible within the viewport.
如果你正在抓取网站,一个非常低效的方法对我来说是突出显示任何元素,然后截图,然后检查截图是否发生了变化。
//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