繁体   English   中英

jQuery 当 div 可见时触发动作的事件

[英]jQuery event to trigger action when a div is made visible

我在我的站点中使用 jQuery,我想在某个 div 可见时触发某些操作。

是否可以将某种“不可见”事件处理程序附加到任意 div,并在 div 可见时运行某些代码?

我想要类似以下伪代码的东西:

$(function() {
  $('#contentDiv').isvisible(function() {
    alert("do something");
  });
});

alert("do something") 代码在 contentDiv 实际可见之前不应触发。

谢谢。

您始终可以添加到原始.show()方法中,这样您就不必在每次显示某些内容或需要它来处理遗留代码时触发事件:

jQuery 扩展:

jQuery(function($) {

  var _oldShow = $.fn.show;

  $.fn.show = function(speed, oldCallback) {
    return $(this).each(function() {
      var obj         = $(this),
          newCallback = function() {
            if ($.isFunction(oldCallback)) {
              oldCallback.apply(obj);
            }
            obj.trigger('afterShow');
          };

      // you can trigger a before show if you want
      obj.trigger('beforeShow');

      // now use the old function to show the element passing the new callback
      _oldShow.apply(obj, [speed, newCallback]);
    });
  }
});

用法示例:

jQuery(function($) {
  $('#test')
    .bind('beforeShow', function() {
      alert('beforeShow');
    }) 
    .bind('afterShow', function() {
      alert('afterShow');
    })
    .show(1000, function() {
      alert('in show callback');
    })
    .show();
});

这有效地让您在执行 beforeShow 和 afterShow 的同时仍然执行原始 .show() 方法的正常行为。

您还可以创建另一个方法,这样您就不必覆盖原来的 .show() 方法。

DOM 突变观察者正在解决这个问题。 它们允许您将观察者(一个函数)绑定到更改 dom 元素的内容、文本或属性的事件。

随着IE11的发布,各大浏览器都支持这个功能,查看http://caniuse.com/mutationobserver

示例代码如下:

 $(function() { $('#show').click(function() { $('#testdiv').show(); }); var observer = new MutationObserver(function(mutations) { alert('Attributes changed!'); }); var target = document.querySelector('#testdiv'); observer.observe(target, { attributes: true }); });
 <div id="testdiv" style="display:none;">hidden</div> <button id="show">Show hidden div</button> <script type="text/javascript" src="https://code.jquery.com/jquery-1.9.1.min.js"></script>

没有您可以为此挂钩的本机事件,但是您可以在使用 . 触发功能

例如

//declare event to run when div is visible
function isVisible(){
   //do something

}

//hookup the event
$('#someDivId').bind('isVisible', isVisible);

//show div and trigger custom event in callback when div is visible
$('#someDivId').show('slow', function(){
    $(this).trigger('isVisible');
});

您可以使用 jQuery 的Live Query 插件 并编写代码如下:

$('#contentDiv:visible').livequery(function() {
    alert("do something");
});

然后每次 contentDiv 可见时,“做某事”都会被提醒!

redsquare 的解决方案是正确的答案。

但是作为理论中的解决方案,您可以编写一个函数来选择由.visibilityCheck分类的元素(不是所有可见元素)并检查它们的visibility属性值; 如果是true那么做点什么。

之后,应使用setInterval()函数定期执行该函数。 您可以在成功调用后使用clearInterval()停止计时器。

下面是一个例子:

function foo() {
    $('.visibilityCheck').each(function() {
        if ($(this).is(':visible')){
            // do something
        }
    });
}

window.setInterval(foo, 100);

您还可以对其进行一些性能改进,但是,该解决方案在实际中使用起来基本上是荒谬的。 所以...

以下代码(来自http://maximeparmentier.com/2012/11/06/bind-show-hide-events-with-jquery/ )将使您能够使用$('#someDiv').on('show', someFunc); .

(function ($) {
  $.each(['show', 'hide'], function (i, ev) {
    var el = $.fn[ev];
    $.fn[ev] = function () {
      this.trigger(ev);
      return el.apply(this, arguments);
    };
  });
})(jQuery);

如果要在所有实际可见的元素(和子元素)上触发事件,通过 $.show、toggle、toggleClass、addClass 或 removeClass:

$.each(["show", "toggle", "toggleClass", "addClass", "removeClass"], function(){
    var _oldFn = $.fn[this];
    $.fn[this] = function(){
        var hidden = this.find(":hidden").add(this.filter(":hidden"));
        var result = _oldFn.apply(this, arguments);
        hidden.filter(":visible").each(function(){
            $(this).triggerHandler("show"); //No bubbling
        });
        return result;
    }
});

现在你的元素:

$("#myLazyUl").bind("show", function(){
    alert(this);
});

您可以通过将它们添加到顶部的数组(如“attr”)来为其他 jQuery 函数添加覆盖

一个基于 Glenns ideea 的隐藏/显示事件触发器:删除了切换,因为它会触发显示/隐藏,我们不希望一个事件有 2 个触发

$(function(){
    $.each(["show","hide", "toggleClass", "addClass", "removeClass"], function(){
        var _oldFn = $.fn[this];
        $.fn[this] = function(){
            var hidden = this.find(":hidden").add(this.filter(":hidden"));
            var visible = this.find(":visible").add(this.filter(":visible"));
            var result = _oldFn.apply(this, arguments);
            hidden.filter(":visible").each(function(){
                $(this).triggerHandler("show");
            });
            visible.filter(":hidden").each(function(){
                $(this).triggerHandler("hide");
            });
            return result;
        }
    });
});

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

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

根据您的示例,您将如何使用它:

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

在这里帮助我的是最近的ResizeObserver 规范 polyfill

const divEl = $('#section60');

const ro = new ResizeObserver(() => {
    if (divEl.is(':visible')) {
        console.log("it's visible now!");
    }
});
ro.observe(divEl[0]);

请注意,它是跨浏览器和高性能的(无轮询)。

使用 jQuery 航点:

$('#contentDiv').waypoint(function() {
   alert('do something');
});

jQuery Waypoints 站点其他示例。

我做了一个简单的 setinterval 函数来实现这一点。 如果类 div1 的元素可见,则将 div2 设置为可见。 我不知道一个好的方法,但一个简单的修复。

setInterval(function(){
  if($('.div1').is(':visible')){
    $('.div2').show();
  }
  else {
    $('.div2').hide();
  }      
}, 100);

只需将触发器与选择器绑定并将代码放入触发器事件中:

jQuery(function() {
  jQuery("#contentDiv:hidden").show().trigger('show');

  jQuery('#contentDiv').on('show', function() {
    console.log('#contentDiv is now visible');
    // your code here
  });
});

您也可以尝试并行线程中提到的jQuery 出现插件https://stackoverflow.com/a/3535028/741782

这支持动画完成后的缓动和触发事件! [在 jQuery 2.2.4 上测试]

(function ($) {
    $.each(['show', 'hide', 'fadeOut', 'fadeIn'], function (i, ev) {
        var el = $.fn[ev];
        $.fn[ev] = function () {
            var result = el.apply(this, arguments);
            var _self=this;
            result.promise().done(function () {
                _self.triggerHandler(ev, [result]);
                //console.log(_self);
            });
            return result;
        };
    });
})(jQuery);

灵感来自http://viralpatel.net/blogs/jquery-trigger-custom-event-show-hide-element/

有一个 jQuery 插件可用于观察 DOM 属性的变化,

https://github.com/darcyclarke/jQuery-Watch-Plugin

插件包装你需要做的就是绑定 MutationObserver

然后,您可以使用它来观看 div:

$("#selector").watch('css', function() {
    console.log("Visibility: " + this.style.display == 'none'?'hidden':'shown'));
    //or any random events
});

希望这将以最简单的方式完成工作:

$("#myID").on('show').trigger('displayShow');

$('#myID').off('displayShow').on('displayShow', function(e) {
    console.log('This event will be triggered when myID will be visible');
});

我根据 Glenns 的想法更改了 Catalint 的隐藏/显示事件触发器。 我的问题是我有一个模块化的应用程序。 我在显示和隐藏 div 父级的模块之间切换。 然后,当我隐藏一个模块并显示另一个模块时,使用他的方法,当我在模块之间切换时,我有一个明显的延迟。 我只需要有时来点亮这个事件,并且在一些特殊的孩子身上。 所以我决定只通知“displayObserver”类的孩子

$.each(["show", "hide", "toggleClass", "addClass", "removeClass"], function () {
    var _oldFn = $.fn[this];
    $.fn[this] = function () {
        var hidden = this.find(".displayObserver:hidden").add(this.filter(":hidden"));
        var visible = this.find(".displayObserver:visible").add(this.filter(":visible"));
        var result = _oldFn.apply(this, arguments);
        hidden.filter(":visible").each(function () {
            $(this).triggerHandler("show");
        }); 
        visible.filter(":hidden").each(function () {
            $(this).triggerHandler("hide");
        });
        return result;
    }
});

然后当孩子想听“显示”或“隐藏”事件时,我必须给他添加“displayObserver”类,当它不想继续收听时,我将他的类删除

bindDisplayEvent: function () {
   $("#child1").addClass("displayObserver");
   $("#child1").off("show", this.onParentShow);
   $("#child1").on("show", this.onParentShow);
},

bindDisplayEvent: function () {
   $("#child1").removeClass("displayObserver");
   $("#child1").off("show", this.onParentShow);
},

我希望帮助

一种方法来做到这一点。
仅适用于由 css 类更改引起的可见性更改,但也可以扩展以监视属性更改。

var observer = new MutationObserver(function(mutations) {
        var clone = $(mutations[0].target).clone();
        clone.removeClass();
                for(var i = 0; i < mutations.length; i++){
                    clone.addClass(mutations[i].oldValue);
        }
        $(document.body).append(clone);
        var cloneVisibility = $(clone).is(":visible");
        $(clone).remove();
        if (cloneVisibility != $(mutations[0].target).is(":visible")){
            var visibilityChangedEvent = document.createEvent('Event');
            visibilityChangedEvent.initEvent('visibilityChanged', true, true);
            mutations[0].target.dispatchEvent(visibilityChangedEvent);
        }
});

var targets = $('.ui-collapsible-content');
$.each(targets, function(i,target){
        target.addEventListener('visibilityChanged',VisbilityChanedEventHandler});
        target.addEventListener('DOMNodeRemovedFromDocument',VisbilityChanedEventHandler });
        observer.observe(target, { attributes: true, attributeFilter : ['class'], childList: false, attributeOldValue: true });
    });

function VisbilityChanedEventHandler(e){console.log('Kaboom babe'); console.log(e.target); }

我的解决方案:

; (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
}
$( window ).scroll(function(e,i) {
    win_top = $( window ).scrollTop();
    win_bottom = $( window ).height() + win_top;
    //console.log( win_top,win_bottom );
    $('.onvisible').each(function()
    {
        t = $(this).offset().top;
        b = t + $(this).height();
        if( t > win_top && b < win_bottom )
            alert("do something");
    });
});

 $(function() { $(document).click(function (){ if ($('#contentDiv').is(':visible')) { alert("Visible"); } else { alert("Hidden"); } }); });
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div id="contentDiv">Test I'm here</div> <button onclick="$('#contentDiv').toggle();">Toggle the div</button>

<div id="welcometo">Özhan</div>
<input type="button" name="ooo" 
       onclick="JavaScript:
                    if(document.all.welcometo.style.display=='none') {
                        document.all.welcometo.style.display='';
                    } else {
                        document.all.welcometo.style.display='none';
                    }">

此代码自动控制不需要查询可见或不可见控制

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM