什么时候元素可见的事件监听器?


113

我正在构建一个要包含在页面中的工具栏。将要包含的div将默认为display:none。有什么方法可以在我的工具栏上放置一个事件侦听器,以便在它可见时进行侦听,以便可以初始化?还是我必须将其从包含页面传递给变量?

谢谢



@kangax,谢谢。但是由于它没有得到广泛实施,我想我将抓紧整个事件监听器的思路,并走另一条路。
JD Isaacks 09年

请参见以下答案,以了解JavaScript中“ onVisible”事件的实现:stackoverflow.com/a/3807340/975097
Anderson Green


Answers:


8

Javascript事件处理用户交互,如果您的代码组织得足够好,则应该可以在可见性发生变化的同一位置调用初始化函数(即,您不应该myElement.style.display在很多地方进行更改,而是调用执行该功能的方法/方法)这个以及您可能想要的其他任何东西)。


8
但是,您如何能够检测到可见性的变化(即,一旦元素变为可见,就调用函数)?
安德森·格林

我想你不能那样做。您将要做的是确切地知道更改的原因,然后将您的电话放在那儿,而不是尝试检测更改。如果可见性的变化不是您自己的代码直接负责的(例如,某些lib),并且发生这种情况的逻辑是非常人为的,那么我想您很走运吗?:)
maltalef

6
我否决了这个问题,因为尽管它具有所有意义,但与实际问题无关。(如果我在框架上不显示任何内容,则所有子元素均不可见)
Sebas

2
@Sebas,我真的不明白为什么孩子们的视野在这里很重要。无论如何,如果答案对您的特定情况没有用(无论可能如何),但指向大多数程序员一个解决方案(或解释为什么没有解决方案),那么我的拙见仍然是一个有效的答案。如果您更喜欢其他答案中的一个(尤其是在以后的某个时间,当技术得到改进并且有新的选择可用时),我认为更改正确答案的请求比拒绝投票更合适。无论如何,感谢您的单挑:)
maltalef

2
@figha,不是孩子,但是如果您正在查看的元素在显示为无的框架中,则不会有任何迹象。
塞巴(Sebas)2013年

66

展望未来,您正在寻找新的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);
}

实际中:https : //jsfiddle.net/elmarj/u35tez5n/5/


2
> Intersection Observer API允许您配置一个回调,只要一个元素(称为目标)与设备视口或指定元素相交,就会调用该回调。
stil

1
请注意,目前InteractionObserver在Safari上不起作用。caniuse.com/#feat=intersectionobserver似乎有一个修补程序正在进行中。bugs.webkit.org/show_bug.cgi?id=159475
Pic Mickael,

8
IE何时缺乏对此类酷事的支持,以免破坏我们的生活?
彼得·摩尔

5
@PeterMoore只要您停止尝试就可以了。只是不要。
johny为什么

4
大声笑。有时这不是我们的决定。
彼得·摩尔

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

我可能会晚一点,但是您可以使用MutationObserver观察所需元素的任何更改。如果发生任何更改,则只需检查是否显示了该元素。


4
当未显示targetNode时,此方法不起作用,因为未显示祖先,但随后显示了祖先。
Marco Eckstein '18

已投票!:我在另一个计算器的答案用这个stackoverflow.com/questions/48792245/...
尼克·蒂默

不幸的是,这仅在元素上使用内联样式时才有效,而当更改是CSS类更改的结果时则无效(这是更可能的情况,因为在以前的情况下您可能已经具有完整的程序控制权)。显示该问题的Fiddle:jsfiddle.net/elmarj/uye62Lxc/4。有关如何观察样式更改的更完整讨论,请参见此处:dev.to/oleggromov/observing-style-changes--d4f
Elmar Jansen

其实正确的观察用在这里将是一个IntersectionObserver- stackoverflow.com/a/52627221/2803743
卡诺

当您要切换元素的开和关,并且不能直接控制该元素,并且想对显示值的变化做出反应时,此解决方案非常有用
Eran Goldin

15

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

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

这段代码是我的头等大事,所以我不确定它是否有效。

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


1
有趣,谢谢。几年后,DOMAttrModified的状态发生了变化:“已弃用。此功能已从Web标准中删除。尽管某些浏览器可能仍支持此功能,但它正在被删除。” (Mozilla)
BurninLeo



7

如@figha所说,如果这是您自己的网页,则在使元素可见后,只需运行需要运行的任何内容。

但是,出于回答问题(以及任何使用Chrome或Firefox扩展程序的人,这是一个常见的用例)的目的,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);

反应包括addedremovedvalueChanged和更多valueChanged包括所有属性,包括display等。


可能是因为他想知道它何时真正出现在屏幕上。我愿意,我只能假设下选者有相同的原因。
Dave Hillier

不回答问题,不建议仅发布链接。
Alex Holsgrove

@AlexHolsgrove我从链接中添加了一个示例。由于发布者谈论的是在页面上添加工具栏,因此似乎他们可能正在将工具栏添加到第三方页面上,并等待将元素添加到DOM,在这种情况下,Mutations是最好的API。
mikemaccana

请注意,这还不包括这部分解释了其中的突变观察过程中“知名度”的用武之地
迈克Pomax“Kamermans


3

仅在评论DOMAttrModified事件侦听器浏览器支持时:

跨浏览器支持

在不同的浏览器中,这些事件的实现方式不一致,例如:

  • 版本9之前的IE根本不支持突变事件,并且在版本9中无法正确实现其中的某些事件(例如DOMNodeInserted)

  • WebKit不支持DOMAttrModified(请参阅webkit错误8191和解决方法)

  • Firefox(自版本11起)不支持“突变名称事件”,即DOMElementNameChanged和DOMAttributeNameChanged,并且在其他浏览器中也不受支持。

来源:https : //developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events


-2

我的解决方案:

; (function ($) {
$.each([ "toggle", "show", "hide" ], function( i, name ) {
    var cssFn = $.fn[ name ];
    $.fn[ name ] = function( speed, easing, callback ) {
        if(speed == null || typeof speed === "boolean"){
            var ret=cssFn.apply( this, arguments )
            $.fn.triggerVisibleEvent.apply(this,arguments)
            return ret
        }else{
            var that=this
            var new_callback=function(){
                callback.call(this)
                $.fn.triggerVisibleEvent.apply(that,arguments)
            }
            var ret=this.animate( genFx( name, true ), speed, easing, new_callback )
            return ret
        }
    };
});

$.fn.triggerVisibleEvent=function(){
    this.each(function(){
        if($(this).is(':visible')){
            $(this).trigger('visible')
            $(this).find('[data-trigger-visible-event]').triggerVisibleEvent()
        }
    })
}
})(jQuery);

例如:

if(!$info_center.is(':visible')){
    $info_center.attr('data-trigger-visible-event','true').one('visible',processMoreLessButton)
}else{
    processMoreLessButton()
}

function processMoreLessButton(){
//some logic
}

5
您应该告诉所有人,您已经使用了原始jQuery的代码,这会激发更多的信心;)
2014年

1
“我的解决方案”。这个家伙很神经。
安德烈席尔瓦

@AndréSilva也许他写了jQuery。:O
安德鲁
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.