divが表示されたときにアクションをトリガーするjQueryイベント


312

私のサイトではjQueryを使用していますが、特定のdivが表示されたときに特定のアクションをトリガーしたいと思います。

ある種の「isvisible」イベントハンドラーを任意のdivにアタッチし、divが表示されるときに特定のコードを実行することは可能ですか?

次の疑似コードのようなものが欲しい:

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

contentDivが実際に表示されるまで、alert( "何かを行う")コードは起動しないでください。

ありがとう。


回答:


190

常に元の.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()メソッドの通常の動作を実行しながら、beforeShowおよびafterShowを効果的に実行できます。

別のメソッドを作成して、元の.show()メソッドをオーバーライドする必要がないようにすることもできます。


7
編集:このメソッドには欠点が1つだけあります:要素を表示するすべてのメソッドに対して同じ「拡張」を繰り返す必要があります:show()、slideDown()など。この問題を一度に解決するには、より普遍的なものが必要です。すべて、delegate()またはlive()の「準備完了」イベントを持つことは不可能だからです。
Shahriyar Imanov

1
良い、唯一の問題は、fadeToこの関数を実装した後、関数が正しく機能しないことです
Omid

9
あなたのコードは最新のjQuery(このコメントの日付では1.7.1)で動作しないようです。:私は、最新のjQueryを使っての作業に少しこのソリューションを再加工しているstackoverflow.com/a/9422207/135968
mkmurray

1
ajax応答によってトリガーされるdiv可視性でそのコードを機能させることができません。
JackTheKnife 2016年

初心者はこちら。apply()で確認できるように、obj(およびnewCallback)がfunction()宣言の外で参照できる理由がわかりません。varで宣言すると変数はローカルになりますが、「var」を削除すると変数は自動的にグローバルになると教えられました。
Yuta73

85

この問題は、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>


3
IEでまだサポートされていないのは残念です。caniuse.com/mutationobserver- >それをサポートするブラウザーを表示します。
ccsakuweb 2013

2
これは実際に機能し、レガシーブラウザをサポートする必要がないため、完璧です。私はここに答えのJSFiddle証明を追加しました:jsfiddle.net/DanAtkinson/26URF
Dan Atkinson

Chromeではうまく機能しますが、Blackberry 10カスケードWebビューでは機能しません(他の誰かが気にかけている場合は;))
Guillaume Gendre

1
監視対象の祖先の属性変更によって可視性が変化する場合、これは機能しないようです。
マイケル、

4
これはChrome 51では機能しないようです。理由は不明です。上記のコードを実行してボタンを押すと、警告は表示されません。
クリス

76

このためにフックできるネイティブイベントはありませんが、を使用して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');
});

45
ここでの私の制限は、show()のdivであるコードに必ずしもアクセスできる必要がないことです。そのため、trigger()メソッドを実際に呼び出すことはできません。
フランカデリック2009

11
JSは私の組織外の開発チームによって提供されました。これは「ブラックボックス」のようなものでもあるため、可能であればそのコードを変更したくありません。それは私たちの唯一の選択かもしれません。
フランカデリック2009

あなたはいつでもあなた自身の実装でそれらのjs関数を上書きすることができます。しかし、厳しく聞こえます!
redsquare 2009

11
@redsquare:show()上記のコードブロック以外の複数の場所から呼び出された場合はどうなりますか?
Robin Maben、2011

1
この例でonIsVisibleは、 "isVisible"の使用が少しあいまいであるため、関数名をに変更する必要があります。
Brad Johnson、

27

jQueryのLive Queryプラグインを使用できます。次のようにコードを記述します。

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

その後、contentDivが表示されるたびに、「何かをする」ことが通知されます。


まあ、それはうまくいきます。私はそれについて考え、それを試すことなく機能する可能性が低いとして拒否しました。試してみるべきだった。:)
neminem

1
私のために働いていませんでした。「livequeryは関数ではありません」というエラーが表示されます。「jquery-1.12.4.min.js」と「jquery-3.1.1.min.js」の両方を試しました
Paul Gorbas

2
@Paul:プラグインです
Christian

これはあなたのウェブサイトをかなり遅くするかもしれません!livequeryプラグインは、DOM変異オブザーバーなどの最新の効率的なメソッドを使用するのではなく、属性の高速ポーリングを実行します。@hegemonの解決策を好む:stackoverflow.com/a/16462443/19163(およびポーリングを古いIEバージョンのフォールバックとしてのみ使用)– vog 1時間前
vog

20

redsquareのソリューションが正解です。

しかし、IN-THEORYソリューションとして、.visibilityCheckすべての可視要素ではなく)によって分類された要素を選択する関数を記述し、それらのvisibilityプロパティ値を確認できます。もしtrueそうなら何かをします。

その後、この機能を使用して定期的に機能を実行する必要がありsetInterval()ます。を使用してタイマーを停止できますclearInterval()コールアウトが成功したらをてます。

次に例を示します。

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

window.setInterval(foo, 100);

また、パフォーマンスを改善することもできますが、実際にソリューションを使用するのはばかげています。そう...


5
setTimeout / setInterval内で暗黙のfuncを使用するのは適切ではありません。setTimeoutを使用(FOO、100)
redsquare

1
私はあなたにそれを手渡さなければなりません、これは厄介ではありますが、創造的です。そしてそれは、IE8に準拠した方法で私のためにトリックを実行するのに十分速くて汚いものでした。ありがとうございました!
JD Smith

またはdisplay:none
マイケル

12

次のコード(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);

8
これは私にとっては完璧に機能しましたが、関数が表示と非表示の関数のチェーンを壊すことに注意することが重要です。これは多くのプラグインを壊します。el.apply(this, arguments)これを修正するには、前に改行を追加します。
jaimerump 2013

これは私が探していたものです!@jaimerumpからのコメントのように、リターンを追加する必要があります
Brainfeeder

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

そして今あなたの要素:

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

追加のjQuery関数にオーバーライドを追加できます( "attr"など)。


9

Glenns ideeaに基づく非表示/表示イベントトリガー:表示/非表示を起動し、1つのイベントに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;
        }
    });
});

2
attrとremoveAttrもチェックする必要がありますか?
Andrija

5

私はこれと同じ問題を抱えており、私たちのサイトでそれを解決するためのjQueryプラグインを作成しました。

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

あなたの例に基づいてそれをどのように使用するかは次のとおりです:

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

1
ポーリングはあまり効率的ではなく、多くの要素に使用するとブラウザの速度が大幅に低下します。
Cerin、2016年

4

jQuery Waypointsを使用します。

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

jQuery Waypointsサイトの他の例。


1
これは、スクロールのために項目が表示される場合にのみ機能し、他のプログラム上の変更によるものではありません。
AdamJones 14年

@AdamJonesキーボードを使用している場合、期待どおりに動作します。例:imakewebthings.com/jquery-waypoints/shortcuts/infinite-scroll
Fedir RYKHTIK 2014年

4

ここで私を助けたのは、最近のResizeObserver仕様のポリフィルです。

const divEl = $('#section60');

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

クロスブラウザであり、パフォーマンスも高いことに注意してください(ポーリングなし)。


他とは異なり、テーブルの行が表示/非表示になるたびに検出するのにうまくいきました。また、必要なプラグインがなかったこともプラスです。
BrettC

3

これを実現するために、単純なsetinterval関数を実行しました。クラスdiv1の要素が表示される場合、div2が表示されるように設定します。私は良い方法ではありませんが、簡単な修正を知っています。

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


2

これは、アニメーションの終了後のイージングとトリガーイベントをサポートします![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);

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


2

トリガーをセレクターにバインドして、コードをトリガーイベントに配置するだけです。

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

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

これは非常にエレガントなソリューションだと思います。それは私のために働いた。
KIKOソフトウェア

1

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

1

これが最も簡単な方法で仕事をすることを願っています:

$("#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のアイデアに基づいて、非表示/表示イベントトリガーを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);
},

助けが欲しい


0

これを行う1つの方法。
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); }

0

私の解決策:

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

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

このコード自動コントロールはクエリの表示または非表示のコントロールを必要としません

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.