JS:元素变得可见时的事件监听器?

JD *_*cks 94 javascript

我正在构建一个将包含在页面中的工具栏.它将被包括在内的div将默认为display:none.有没有办法我可以在我的工具栏上放置一个事件监听器,以便在它变得可见时进行监听,以便初始化?或者我是否必须从包含页面传递变量?

谢谢

Elm*_*sen 46

展望未来,新的HTML Intersection Observer API是您正在寻找的东西.它允许您配置一个称为目标的元素与设备视口或指定元素相交时调用的回调.它可用于最新版本的Chrome,Firefox和Edge.有关详细信息,请参阅https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API.

观察显示的简单代码示例:无切换:

// Start observing visbility of element. On change, the
//   the callback is called with Boolean visibility as
//   argument:

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);
}
Run Code Online (Sandbox Code Playgroud)

在行动:https://jsfiddle.net/elmarj/u35tez5n/5/

  • IE何时缺乏对此类酷事的支持,以免破坏我们的生活? (5认同)
  • > Intersection Observer API允许您配置一个回调,只要一个元素(称为目标)与设备视口或指定元素相交,就会调用该回调。 (2认同)
  • @PeterMoore只要您停止尝试就可以了。只是不要。 (2认同)
  • 大声笑。有时这不是我们的决定。 (2认同)

joe*_*joe 43

如果您只想在元素在视口中可见时运行一些代码:

function 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);
}
Run Code Online (Sandbox Code Playgroud)

当元素变得可见(轻微事件)时,交集观察者会调用callback并用 销毁自身.disconnect()

像这样使用它:

onVisible(document.querySelector("#myElement"), () => console.log("it's visible"));
Run Code Online (Sandbox Code Playgroud)

或者像这样:

await onVisible(document.querySelector("#myElement"));
console.log("it's visible");
Run Code Online (Sandbox Code Playgroud)

如果您希望在元素完全可见时触发回调,那么您应该更改entry.intersectionRatio > 0entry.intersectionRatio === 1.

如果在调用 时该元素已经可见onVisible,则回调将立即触发。

相关:如果您想立即获取true或来了解该元素当前false是否可见,请使用此代码(更改以满足您的要求)。intersectionRatio

  • 这应该是公认的答案。 (3认同)

小智 34

var targetNode = document.getElementById('elementId');
var observer = new MutationObserver(function(){
    if(targetNode.style.display != 'none'){
        // doSomething
    }
});
observer.observe(targetNode, { attributes: true, childList: true });
Run Code Online (Sandbox Code Playgroud)

我可能有点晚了,但您可以使用MutationObserver观察所需元素的任何变化.如果发生任何更改,您只需检查元素是否显示.

  • 这在 targetNode 未显示时不起作用,因为祖先未显示但随后被显示。 (8认同)

sli*_*kts 14

至少有一种方法,但它不是一个很好的方法.您可以只轮询元素以进行更改,如下所示:

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);
Run Code Online (Sandbox Code Playgroud)

DOM标准还指定了突变事件,但我从未有机会使用它们,我不确定它们的支持程度如何.你会像这样使用它们:

target.addEventListener('DOMAttrModified', function()
{
    if (e.attrName == 'style') {
        alert('style changed');
    }
}, false);
Run Code Online (Sandbox Code Playgroud)

这段代码不在我的脑海中,所以我不确定它是否有效.

最好的,最简单的解决办法是在显示你的目标功能的回调.

  • 有趣,谢谢。几年后,DOMAttrModified 的状态发生了变化:“已弃用。此功能已从 Web 标准中删除。尽管某些浏览器可能仍然支持它,但它正在被删除。” (火狐) (2认同)
  • [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) 是新的。 (2认同)

Sha*_*owe 14

我有同样的问题,并创建了一个jQuery插件来解决我们的网站.

https://github.com/shaunbowe/jquery.visibilityChanged

以下是根据您的示例使用它的方法:

$('#contentDiv').visibilityChanged(function(element, visible) {
    alert("do something");
});
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案使用`.is(':visible')`和`setTimeout`。 (2认同)

mal*_*lef 12

Javascript事件处理用户交互,如果你的代码足够有条理,你应该能够在可见性发生变化的同一个地方调用初始化函数(即你不应该myElement.style.display在很多地方改变,而是调用一个函数/方法这和你可能想要的任何其他东西).

  • 但是,您如何能够检测到可见性的变化(即,一旦元素变得可见就调用函数)? (8认同)
  • 我对这个问题进行了贬低,因为尽管它具有所有意义,但它与实际问题无关.(如果我在框架上没有显示任何内容,则所有子元素都将变为不可见) (4认同)
  • @Sebas,我真的不明白为什么孩子们的能见度在这里很重要。无论如何,如果答案对您的特殊情况没有用(无论可能如何),但指向大多数程序员一个解决方案(或解释为什么没有解决方案),那么我的拙见仍然是一个有效的答案。如果您更喜欢其他答案中的一个(尤其是在后来的某个时候,当技术得到改进并且有新的选择可用时),我认为更改正确答案的请求比拒绝表决更合适。无论如何,请多加注意:) (2认同)
  • @figha,而不是孩子,但如果您正在观看的元素位于显示的帧=无,则您将不会有任何迹象. (2认同)

mik*_*ana 6

正如@figha所说,如果这是你自己的网页,你应该在你使元素可见之后运行你需要运行的任何东西.

但是,为了回答问题(以及任何制作Chrome或Firefox Extensions的人,这是一个常见的用例),Mutation SummaryMutation 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);
Run Code Online (Sandbox Code Playgroud)

反应包括added,removed,valueChanged和更多.valueChanged包括所有属性,包括display等.


Ben*_*ida 6

一个简单的解决方案(甚至适用于嵌套元素)是使用 ResizeObserver。

它应该适用于所有现代浏览器(https://developer.mozilla.org/en-US/docs/Web/API/Resize_Observer_API)。

当一个元素display: none应用了 css 规则(无论是直接还是通过祖先元素)时,它的所有尺寸都将为零。因此,为了检测变得可见,我们只需要一个可见时尺寸非零的元素。

const element = document.querySelector("#element");
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(element)
Run Code Online (Sandbox Code Playgroud)