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

fra*_*lic 303 javascript jquery

我在我的网站中使用jQuery,并且当某个div可见时我想触发某些操作.

是否有可能将某种"isvisible"事件处理程序附加到任意div并且在div可见时运行某些代码?

我想要像下面的伪代码:

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

在实际使contentDiv可见之前,不应触发警报("执行某些操作")代码.

谢谢.

Tre*_*res 188

您始终可以添加到原始.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]);
    });
  }
});
Run Code Online (Sandbox Code Playgroud)

用法示例:

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

这有效地允许您在beforeShow和afterShow之前执行某些操作,同时仍然执行原始.show()方法的正常行为.

您还可以创建另一个方法,这样就不必重写原始的.show()方法.

  • 您的代码似乎不适用于最新的jQuery(本评论发布之日的1.7.1).我稍微修改了这个解决方案以使用最新的jQuery:http://stackoverflow.com/a/9422207/135968 (8认同)
  • 编辑:这种方法只有一个缺点:你必须为揭示元素的所有方法重复相同的"扩展":show(),slideDown()等.需要更多通用的东西来解决这个问题一次和所有,因为它不可能为delegate()或live()提供"就绪"事件. (5认同)
  • 谢谢mkmurray.它至少工作了几年! (3认同)

heg*_*mon 82

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

});
Run Code Online (Sandbox Code Playgroud)
<div id="testdiv" style="display:none;">hidden</div>
<button id="show">Show hidden div</button>

<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
Run Code Online (Sandbox Code Playgroud)

  • 可惜IE还不支持它.http://caniuse.com/mutationobserver - >查看支持它的浏览器. (3认同)
  • 如果可见性更改是由正在监视的祖​​先的属性更改引起的,则这似乎不起作用。 (3认同)
  • 这确实有效,我不需要支持传统浏览器,所以非常完美!我在这里添加了一个JSFiddle证明答案:http://jsfiddle.net/DanAtkinson/26URF/ (2认同)
  • 这似乎不适用于Chrome 51,不知道为什么.运行上面的代码并按下按钮,没有警报. (2认同)

red*_*are 73

没有您可以为此挂钩的本机事件,但是您可以在使用了可见div后从脚本中触发事件.触发功能

例如

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

  • 我的限制是我不一定能访问show()的代码.所以我无法实际调用trigger()方法. (43认同)
  • JS由我组织外的开发团队提供.它也是一个"黑盒子",所以我们不希望在可能的情况下修改该代码.这可能是我们唯一的选择. (11认同)
  • @redsquare:如果从上面讨论的代码块以外的多个地方调用`show()`怎么办? (10认同)

ax0*_*03d 25

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

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

然后,每当contentDiv可见时,"做某事"都会被警告!

  • 没有为我工作。我收到错误“livequery 不是函数”。尝试了“jquery-1.12.4.min.js”和“jquery-3.1.1.min.js” (2认同)
  • @Paul:这是一个插件 (2认同)

sep*_*ehr 20

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

但作为IN-THEORY解决方案,您可以编写一个函数来选择.visibilityCheck(不是所有可见元素)归类的元素并检查它们的visibility属性值; 如果true再做的话.

之后,应该使用该setInterval()功能定期执行该功能.您可以使用clearInterval()成功呼出后停止计时器.

这是一个例子:

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

window.setInterval(foo, 100);
Run Code Online (Sandbox Code Playgroud)

您也可以对其进行一些性能改进,但是,解决方案基本上是荒谬的,无法使用.所以...

  • 在setTimeout/setInterval中使用隐含的func是不好的形式.使用setTimeout(foo,100) (5认同)

Jel*_*Cat 10

以下代码(来自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);
Run Code Online (Sandbox Code Playgroud)

  • 这对我来说非常合适,但重要的是要注意该函数会破坏show和hide函数,从而打破了很多插件.在`el.apply(this,arguments)`前添加一个返回来解决这个问题. (7认同)

小智 9

如果要通过$ .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;
    }
});
Run Code Online (Sandbox Code Playgroud)

现在你的元素:

$("#myLazyUl").bind("show", function(){
    alert(this);
});
Run Code Online (Sandbox Code Playgroud)

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


cat*_*int 9

基于Glenns ideea的隐藏/显示事件触发器:移除切换因为它触发显示/隐藏而我们不希望2fires用于一个事件

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

  • 你也应该检查attr和removeAttr吗? (2认同)

Art*_*iev 6

对我有帮助的是最近的ResizeObserver 规范 polyfill

const divEl = $('#section60');

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

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


Nik*_*yan 6

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

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

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


Sha*_*owe 5

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

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

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

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