событие jQuery для запуска действия, когда div становится видимым

Я использую jQuery на своем сайте, и я хотел бы вызвать определенные действия, когда определенный div становится видимым.

можно ли прикрепить какой-то обработчик событий" isvisible " к произвольным divs и запустить определенный код, когда они div становятся видимыми?

Я хотел бы что-то вроде следующего псевдокода:

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

код предупреждения ("сделать что-то") не должен срабатывать, пока contentDiv не будет фактически сделан видимый.

спасибо.

21 ответов


вы всегда можете добавить к оригинальному .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();
});

это эффективно позволяет вам делать что-то перед шоу и после шоу, все еще Выполняя нормальное поведение оригинала .метод Show.

вы также можете создать другой метод вам не нужно переопределять оригинал .метод Show.


нет собственного события, которое вы можете подключить для этого, однако вы можете вызвать событие из своего сценария после того, как вы сделали 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');
});

проблема решается наблюдатели мутации 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="http://code.jquery.com/jquery-1.9.1.min.js"></script>

вы можете использовать jQuery плагин Live Query. И напишите код следующим образом:

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

тогда каждый раз, когда contentDiv виден," сделать что-то " будет предупрежден!


решение redsquare это правильный ответ.

, а как теоретическое решение вы можете написать функцию, которая выбирает элементы классифицируются по .visibilityCheck (не все видимые элементы) и проверить их visibility значение свойства; если true тогда сделай что-нибудь.

после этого функция должна периодически выполняться с помощью


следующий код (вытащил из 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);

Если вы хотите вызвать событие для всех элементов (и дочерних элементов), которые фактически сделаны видимыми,$.показать, переключить, 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);
});

вы можете добавить переопределения к дополнительным функциям jQuery, добавив их в массив вверху (например, "attr")


Скрыть/показать события триггера на основе Glenns данные: удален переключатель, потому что он запускает show/hide, и мы не хотим 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;
        }
    });
});

У меня была такая же проблема и я создал плагин jQuery, чтобы решить ее для нашего сайта.

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

вот как вы будете использовать его на основе вашего примера:

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

использовать путевые точки jQuery:

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

другие примеры сайт путевых точек jQuery.


вы также можете попробовать 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/


для просмотра изменений атрибутов DOM доступен плагин jQuery,

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

что помогло мне здесь недавно ResizeObserver spec polyfill:

const divEl = $('#section60');

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

обратите внимание, что это crossbrowser и performant (без опроса).


Я сделал простую функцию setinterval для достижения этого. Если элемент с классом div1 виден, он устанавливает div2 быть видимым. Я знаю не хороший метод, а простое решение.

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

Я изменил триггер события hide/show из Catalint на основе идеи Glenns. Моя проблема заключалась в том, что у меня было модульное приложение. Я переключаюсь между модулями, показывающими и скрывающими родителей divs. Затем, когда я скрываю модуль и показываю другой, с его методом у меня есть видимая задержка при переходе между модулями. Мне нужно только иногда освещать это событие,и в некоторых особых случаях. Поэтому я решил уведомить только детей с классом "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");
    });
});

надеюсь, что это сделает работу самым простым способом:

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

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

<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';
                    }">

этот код автоматического управления не требуется запрос видимый или невидимый элемент управления