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

时间:2009-09-22 19:34:59

标签: javascript

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

由于

11 个答案:

答案 0 :(得分:35)

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

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

>>> my_dict = {'key0': (0, 1), 'key1': (2, 3), 'key2': (4, 5)}
>>> dict_list = []
>>> for key in my_dict:
...    for index, item in enumerate(my_dict[key]):
...       if len(dict_list) >= index + 1:
...           dict_list[index][key] = item
...       else:
...           dict_list.append({key: item})
... 
>>> dict_list
[{'key2': 4, 'key1': 2, 'key0': 0}, {'key2': 5, 'key1': 3, 'key0': 1}]

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

答案 1 :(得分:28)

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

我可能会迟到一点,但你可以使用MutationObserver来观察所需元素的任何变化。如果发生任何更改,您只需检查元素是否显示。

答案 2 :(得分:15)

Javascript 事件处理用户互动,如果您的代码足够有条理,您应该能够在可见性发生变化的同一个地方调用初始化函数(即您不应该在许多地方更改myElement.style.display,而是调用执行此操作的函数/方法以及您可能需要的任何其他内容。

答案 3 :(得分:15)

我遇到了同样的问题并创建了一个jQuery插件来为我们的网站解决它。

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

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

$('#contentDiv').visibilityChanged(function(element, visible) {
    alert("do something");
});

答案 4 :(得分: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);

DOM标准还指定mutation events,但我从未有机会使用它们,我不确定它们的支持程度如何。你会像这样使用它们:

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

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

最佳且最简单的解决方案是在显示目标的函数中进行回调。

答案 5 :(得分:6)

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

但是,为了回答问题(以及制作Chrome或Firefox扩展程序,这是一个常见的用例),Mutation SummaryMutation Observer将允许DOM更改为触发事件。

例如,触发具有data-widget属性的元素的事件被添加到DOM。借用this excellent example from David Walsh's blog

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 and morevalueChanged包含所有属性,包括display等。

答案 6 :(得分:4)

你也可以尝试这个jQuery插件:https://github.com/morr/jquery.appear

答案 7 :(得分:3)

只是评论DO​​MAttrModified事件监听器浏览器支持:

跨浏览器支持

这些事件并非在不同浏览器中一致地实现,例如:

  • 版本9之前的IE根本不支持突变事件 在版本9中没有正确实现其中一些(例如, DOMNodeInserted)

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

  • “变异名称事件”,即DOMElementNameChanged和 Firefox不支持DOMAttributeNameChanged(从版本开始 11),也可能在其他浏览器中。

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

答案 8 :(得分:2)

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

function onVisible(element, callback) {
  new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      if(entry.intersectionRatio > 0) {
        callback(element);
        observer.disconnect();
      }
    });
  }).observe(element);
}

当元素变得可见时,相交观察者调用 callback,然后用 .disconnect() 销毁自身。

像这样使用它:

onVisible(document.querySelector("#myElement"), () => console.log("it's visible"));

答案 9 :(得分:0)

扩展 Elmar 之前的回答,我用它来将焦点放在 Bootstrap 导航栏子菜单中的输入框上。

我希望在展开菜单时将焦点放在搜索框上。 .onfocus() 不起作用,我认为是因为在触发事件时元素不可见(即使使用 mouseup 事件)。不过,这很有效:

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

然后在js中:

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

答案 10 :(得分:-1)

我的解决方案:

; (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
}