Bir div görünür hale getirildiğinde eylemi tetiklemek için jQuery olayı


312

Sitemde jQuery kullanıyorum ve belirli bir div görünür olduğunda belirli eylemleri tetiklemek istiyorum.

Rastgele div'lara bir çeşit "görünmez" olay işleyici eklemek ve div görünür hale getirildiklerinde belirli kod çalıştırmak mümkün müdür?

Aşağıdaki sahte kod gibi bir şey istiyorum:

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

Alert ("bir şey yap") kodu, contentDiv gerçekten görünür hale gelene kadar tetiklenmemelidir.

Teşekkürler.


Yanıtlar:


190

Her zaman bir şey gösterdiğinizde veya eski kodla çalışmanız gerektiğinde olayları tetiklemenize gerek kalmaması için orijinal .show () yöntemine her zaman ekleyebilirsiniz.

Jquery uzantısı:

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

Kullanım örneği:

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

Bu, orijinal .show () yönteminin normal davranışını yürütürken önceShow ve afterShow'dan bir şey yapmanıza olanak tanır.

Orijinal .show () yöntemini geçersiz kılmak zorunda kalmamak için başka bir yöntem de oluşturabilirsiniz.


7
DÜZENLEME: Bu yöntemin yalnızca bir dezavantajı vardır: Show (), slideDown () vb. delegate () veya live () için "hazır" etkinliğe sahip olmanın imkansız olduğu için.
Shahriyar Imanov

1
İyi, tek sorun, bu fadeToişlevi uyguladıktan sonra işlev düzgün çalışmıyor
Omid

9
Kodunuz en son jQuery (bu yorumun tarihinde 1.7.1) ile çalışmıyor gibi görünüyor. En son jQuery ile çalışmak için bu çözümü biraz yeniden
çalıştım

1
Bu kod, bir ajax yanıtı tarafından tetiklenen div görünürlüğü ile çalışamaz.
JackTheKnife

Burada acemi. Neden obj (ve newCallback), geçerli () ifadesinde görüldüğü gibi function () bildirimi dışında başvurulabilir anlamıyorum. Ben var ile bildirmenin değişkenleri yerel kıldığı, ancak "var" ın kaldırılmasının otomatik olarak küresel hale getirdiği öğretildi
Yuta73

85

Sorun DOM mutasyon gözlemcileri tarafından ele alınmaktadır . Değişen içeriği, metni veya dom öğelerinin niteliklerini değiştiren olaylara bir gözlemci (işlev) bağlamanızı sağlar.

IE11'in piyasaya sürülmesiyle tüm büyük tarayıcılar bu özelliği destekliyor, http://caniuse.com/mutationobserver adresini ziyaret edin.

Örnek kod şöyledir:

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


3
IE henüz desteklemiyor yazık. caniuse.com/mutationobserver -> Onu destekleyen tarayıcıları görmek için.
ccsakuweb

2
Bu gerçekten işe yarıyor ve eski tarayıcıları desteklememe gerek yok, bu yüzden mükemmel! Buraya bir JSFiddle kanıtı ekledim: jsfiddle.net/DanAtkinson/26URF
Dan Atkinson

kromda iyi çalışıyor ancak böğürtlen 10 basamaklı web görünümünde çalışmıyor (başka biri umursarsa;))
Guillaume Gendre

1
Görünürlük değişikliğine, izlenen bir atadaki bir öznitelik değişikliğinden kaynaklanıyorsa, bu işe yaramıyor gibi görünmektedir.
Michael

4
Bu, Chrome 51'de çalışmıyor gibi görünüyor, neden olduğundan emin değilim. Yukarıdaki kodu çalıştırmak ve düğmesine basın, uyarı yok.
Kris

76

Bunun için bağlayabileceğiniz yerel bir etkinlik yoktur, ancak div'ı kullanarak div'ı görünür hale getirdikten sonra komut dosyanızdan bir olayı tetikleyebilirsiniz. tetik fonksiyonu

Örneğin

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

45
Buradaki sınırlamam, zorunlu olarak show () 'nin div kodunu gösteren kodlara erişimimin olmamasıdır. Yani aslında trigger () yöntemini çağıramazdım.
frankadelic

11
JS, kuruluşumun dışındaki bir geliştirme ekibi tarafından sağlandı. Aynı zamanda bir "kara kutu" da, bu yüzden mümkünse bu kodu değiştirmek istemiyoruz. Gerçi bizim tek seçimimiz olabilir.
frankadelic

kendi uygulamanızla her zaman js işlevlerini damgalayabilirsiniz. Kulağa korkunç geliyor!
redsquare

11
@redsquare: show()Yukarıda tartışılan kod bloğu dışında birden çok yerden çağrılırsa ne olur ?
Robin Maben

1
Bu örnekte, işlev adını şu şekilde değiştirmelisiniz onIsVisibleçünkü "isVisible" kullanımı şu anda biraz belirsiz.
Brad Johnson

27

JQuery'nin Live Query eklentisini kullanabilirsiniz . Ve kodu aşağıdaki gibi yazın:

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

Sonra contentDiv her görünür olduğunda, "bir şeyler yap" uyarısı verilir!


Şey, bu işe yarıyor. Bunu düşünmüştüm ve denemeden çalışamayacak kadar reddettim. Denemeliydim. :)
neminem

1
Benim için çalışmadı. "Livequery bir işlev değil" hatası alıyorum. Hem "jquery-1.12.4.min.js" hem de "jquery-3.1.1.min.js" ile çalıştı
Paul Gorbas

2
@Paul: Bu bir eklenti
Christian

Bu, web sitenizi önemli ölçüde yavaşlatabilir! Livequery eklentisi, DOM mutasyon gözlemcileri gibi modern verimli yöntemler kullanmak yerine, özellikler üzerinde hızlı yoklama yapar. Bu yüzden @hegemon çözümünü tercih ederim: stackoverflow.com/a/16462443/19163 (ve yoklamayı yalnızca eski IE sürümleri için bir yedek olarak kullanın) - vog 1 saat önce
vog

20

redsquare'in çözümü doğru cevaptır.

Ancak bir IN-THEORY çözümü olarak, .visibilityCheck( tüm görünür öğeler değil ) tarafından sınıflandırılan öğeleri seçen bir işlev yazabilir ve visibilityözellik değerlerini kontrol edebilirsiniz ; eğer bir trueşey yap.

Daha sonra fonksiyon, fonksiyon kullanılarak periyodik olarak gerçekleştirilmelidir setInterval(). clearInterval()Başarılı çağrı üzerine zamanlayıcıyı durdurabilirsiniz .

İşte bir örnek:

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

window.setInterval(foo, 100);

Üzerinde bazı performans iyileştirmeleri de yapabilirsiniz, ancak çözüm temel olarak eylemde kullanılmak için saçmadır. Yani...


5
setTimeout / setInterval içinde zımni bir işlev kullanmak için iyi bir form değil.
SetTimeout

1
Sana teslim etmeliyim, bu yaratıcı, kötü de olsa. Ve IE8 uyumlu bir şekilde benim için hile yapmak için sadece hızlı ve kirli. Teşekkür ederim!
JD Smith

veya display:none?
Michael

12

Aşağıdaki kod ( http://maximeparmentier.com/2012/11/06/bind-show-hide-events-with-jquery/ adresinden alınmıştır ) kullanmanızı sağlayacaktır $('#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);

8
Bu benim için mükemmel çalıştı, ancak fonksiyonun şovda zincirleme kırdığını ve birçok eklentiyi kıran gizleme işlevlerini kırdığını unutmamak önemlidir. el.apply(this, arguments)Bunu düzeltmek için önüne bir dönüş ekleyin .
jaimerump

Aradığım şey buydu! Dönüş, @jaimerump'ın yorumunda olduğu gibi eklenmelidir
Brainfeeder

9

Etkinliği gerçekten görünür hale getirilen tüm öğeler (ve alt öğeler) üzerinde $ .show, toggle, toggleClass, addClass veya removeClass ile tetiklemek istiyorsanız:

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

Ve şimdi öğeniz:

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

Üstteki diziye ekleyerek ek jQuery işlevlerine geçersiz kılmalar ekleyebilirsiniz ("attr" gibi)


9

Glenns ideea'ya dayalı bir gizle / göster olay tetikleyicisi: show / hide'ı tetiklediğinden ve bir etkinlik için 2 ateş istemediğimiz için geçiş kaldırıldı

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

2
Ayrıca attr kontrol ve removeAttr kontrol etmelisiniz?
Andrija

5

Aynı sorunu yaşadım ve sitemiz için çözmek için bir jQuery eklentisi oluşturdum.

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

Örneğinize göre nasıl kullanacağınız aşağıda açıklanmıştır:

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

1
Yoklama çok verimli değildir ve birçok öğe için kullanılmışsa tarayıcıyı önemli ölçüde yavaşlatır.
Cerin


4

Burada bana yardımcı olan en son ResizeObserver spec polyfill :

const divEl = $('#section60');

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

Bu çapraz tarama ve performans (yoklama yok) unutmayın.


Diğerlerinden farklı olarak bir tablo satırı gösterildiğinde / gizlendiğinde tespit etmek için iyi çalıştı, ayrıca bir artı gerekli bir eklenti yoktu!
BrettC

3

Bunu başarmak için basit bir setinterval fonksiyonu yaptım. Div1 sınıfına sahip öğe görünürse, div2 öğesini görünür olacak şekilde ayarlar. İyi bir yöntem değil, basit bir düzeltme biliyorum.

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


2

Bu destek animasyon tamamlandıktan sonra hareket hızı ve tetikleme olayı! [jQuery 2.2.4 üzerinde test edilmiştir]

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

Esinlenerek http://viralpatel.net/blogs/jquery-trigger-custom-event-show-hide-element/


2

Sadece bir tetikleyiciyi seçiciye bağlayın ve kodu trigger olayına yerleştirin:

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

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

Bence bu oldukça zarif bir çözüm. Benim için çalıştı.
KIKO Software

1

DOM özelliklerindeki değişikliği izlemek için bir jQuery eklentisi var,

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

Eklenti tamamlıyor Yapmanız gereken tek şey MutationObserver'ı bağlamak

Sonra div kullanarak izlemek için kullanabilirsiniz:

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

1

Umarım bu işi en basit şekilde yapar:

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

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

0

Glenns fikrine dayanarak Catalint'ten gizle / göster olay tetikleyicisini değiştirdim. Benim sorunum modüler bir uygulama olmasıydı. Div ebeveynlerini gösteren ve gizleyen modüller arasında geçiş yapıyorum. Sonra bir modülü gizlediğimde ve başka bir modül gösterdiğimde, onun yöntemi ile modüller arasında geçiş yaptığımda görünür bir gecikme var. Bazen bu olayı ve bazı özel çocuklarda aydınlatmaya ihtiyacım var. Bu yüzden sadece "displayObserver" sınıfına sahip çocukları bildirmeye karar verdim

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

Sonra bir çocuk "show" veya "hide" olayını dinlemek istediğinde, ona "displayObserver" sınıfını eklemem gerekir ve devam etmek istemediğinde onu sınıftan kaldırırım

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

Yardım isterim


0

Bunu yapmanın bir yolu.
Yalnızca css sınıfı değişikliği tarafından yapılan görünürlük değişikliklerinde çalışır, ancak özellik değişikliklerini izlemek için genişletilebilir.

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

0

çözümüm:

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

örnek kullanım:

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

function processMoreLessButton(){
//some logic
}

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

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

Bu kod otomatik kontrolü sorgu görünür veya görünmez kontrolü gerektirmez

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.