往后看,你需要的是新的HTML Intersection Observer API。它允许您配置一个回调,只要一个元素(称为目标)与设备视口或指定元素相交,就会调用该回调。它在最新版本的Chrome、Firefox和Edge中可用。更多信息请参见https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API。
观察display:none切换的简单代码示例:
// Start observing visbility of element. On change, the
// the callback is called with Boolean visibility as
// argument:
function respondToVisibility(element, callback) {
var options = {
root: document.documentElement,
};
var observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
callback(entry.intersectionRatio > 0);
});
}, options);
observer.observe(element);
}
IntersectionOberver
报告可见性的变化,即使是由父级的可见性决定的,即使这种变化是媒体查询的结果。 - Benoit Blanchonvar targetNode = document.getElementById('elementId');
var observer = new MutationObserver(function(){
if(targetNode.style.display != 'none'){
// doSomething
}
});
observer.observe(targetNode, { attributes: true, childList: true });
我可能有点晚,但你可以使用MutationObserver来观察所需元素上的任何更改。如果发生任何更改,您只需检查该元素是否已显示。
IntersectionObserver
- https://stackoverflow.com/a/52627221/2803743 - kanofunction onVisible(element, callback) {
new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if(entry.intersectionRatio > 0) {
callback(element);
observer.disconnect();
}
});
}).observe(element);
if(!callback) return new Promise(r => callback=r);
}
callback
,然后通过.disconnect()
自行销毁。onVisible(document.querySelector("#myElement"), () => console.log("it's visible"));
await onVisible(document.querySelector("#myElement"));
console.log("it's visible");
entry.intersectionRatio > 0
改为entry.intersectionRatio === 1
。onVisible
时元素已经可见,则回调函数将立即触发。true
或false
,请使用this code(根据你的需求修改intersectionRatio
)。至少有一种方法,但不是很好。您可以像这样轮询元素以检测更改:
var previous_style,
poll = window.setInterval(function()
{
var current_style = document.getElementById('target').style.display;
if (previous_style != current_style) {
alert('style changed');
window.clearInterval(poll);
} else {
previous_style = current_style;
}
}, 100);
DOM标准也规定了变异事件,但我从未有机会使用过它们,也不确定它们的支持程度。您可以像这样使用它们:
target.addEventListener('DOMAttrModified', function()
{
if (e.attrName == 'style') {
alert('style changed');
}
}, false);
这段代码是我凭空想出来的,所以我不确定它是否有效。
最好且最简单的解决方案是在显示目标的函数中添加一个回调函数。
我曾经也遇到过这个问题,为了解决我们网站上的问题,我创建了一个 jQuery 插件。
https://github.com/shaunbowe/jquery.visibilityChanged
以下是根据您的示例使用它的方法:
$('#contentDiv').visibilityChanged(function(element, visible) {
alert("do something");
});
.is(':visible')
以及setTimeout
。 - Hp93如@figha所说,如果这是你自己的网页,你只需要在使元素可见后运行所需的内容。
但是,为了回答问题(以及任何制作Chrome或Firefox扩展程序的人,其中这是常见用例),Mutation Summary 和 Mutation Observer 可以允许DOM更改触发事件。
例如,触发具有data-widget
属性添加到DOM中的元素的事件。借鉴David Walsh博客上的这个绝妙示例:
var observer = new MutationObserver(function(mutations) {
// For the sake of...observation...let's output the mutation to console to see how this all works
mutations.forEach(function(mutation) {
console.log(mutation.type);
});
});
// Notify me of everything!
var observerConfig = {
attributes: true,
childList: true,
characterData: true
};
// Node, config
// In this case we'll listen to all changes to body and child nodes
var targetNode = document.body;
observer.observe(targetNode, observerConfig);
响应包括 added
, removed
, valueChanged
和更多。valueChanged
包括所有属性,包括 display
等。
即使对于嵌套元素,这个简单的解决方案也可以使用 ResizeObserver。
它应该适用于所有现代浏览器 (https://developer.mozilla.org/en-US/docs/Web/API/Resize_Observer_API)
当一个元素应用了css规则display:none
(无论是通过直接设置还是通过祖先元素设置)时,它的所有尺寸将为零。因此,为了检测到其变得可见,我们只需要在可见时具有非零尺寸的元素。
const block=document.querySelector("#the-block")
const resizewatcher=new ResizeObserver(entries => {
for (const entry of entries){
console.log("Element",entry.target,
(entry.contentRect.width == 0) ?
"is now hidden" :
"is now visible"
)
}
})
resizewatcher.observe(block)
ResizeObserver
可以解决Web组件定义顺序混乱的问题。有时,在触发connectedCallback
时元素尚未被调整大小。 - ShortFuse关于DOMAttrModified事件监听器的浏览器支持,需要进行评论:
跨浏览器支持
这些事件在不同的浏览器中实现不一致,例如:
IE 9之前的版本根本不支持突变事件,并且在版本9中无法正确实现其中某些事件(例如DOMNodeInserted)
WebKit不支持DOMAttrModified(请参见webkit bug 8191和解决方法)
“mutation name events”,即DOMElementNameChanged和DOMAttributeNameChanged在Firefox中不受支持(截至版本11),可能在其他浏览器中也是如此。
来源:https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events
MutationObserver
。Mutation Events
已被弃用。https://dev59.com/tWIj5IYBdhLWcg3wTDVn - Code NoviceMutationObserver
代替。Mutation Events
已被弃用。https://stackoverflow.com/questions/20420577/detect-added-element-to-dom-with-mutation-observer - undefined在Elmar之前的回答的基础上,我使用了这个方法来将焦点放在Bootstrap导航栏子菜单中的输入框上。
当展开菜单时,我希望焦点放在搜索框上。.onfocus()没有起作用,我认为是因为元素在触发事件时不可见(即使是鼠标抬起事件)。但这个方法完美地解决了问题:
<ul class="navbar-nav ms-auto me-0 ps-3 ps-md-0">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" title="Search" id="navbardrop" data-bs-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-search"></i>
</a>
<div class="dropdown-menu dropdown-menu-end search-menu">
<form action="{% url 'search' %}" method="get">
<div class="form-group row g-1 my-1 pb-1">
<div class="col">
<input type="text" name="query" id="searchbox" class="form-control py-1 ps-2" value="{% if search_query %}{{ search_query }}{% endif %}">
</div>
<div class="col-auto">
<input type="submit" value="Search" class="btn-primary form-control py-1">
</div>
</div>
</form>
</div>
</li>
</ul>
respondToVisibility = function (element, callback) {
var options = {
root: document.documentElement,
};
var observer = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
callback(entry.intersectionRatio > 0);
});
}, options);
observer.observe(element);
};
respondToVisibility(document.getElementById("searchbox"), (visible) => {
if (visible) {
document.getElementById("searchbox").focus();
}
});
Javascript 事件处理与用户交互有关,如果您的代码足够有组织性,您应该能够在可见性更改的同一位置调用初始化函数(即,您不应该在许多地方更改myElement.style.display
,而是调用一个执行此操作和其他任何您可能需要的操作的函数/方法)。