div가 표시 될 때 작업을 트리거하는 jQuery 이벤트


312

내 사이트에서 jQuery를 사용하고 있으며 특정 div가 표시되면 특정 작업을 트리거하고 싶습니다.

임의의 div에 일종의 "보이지 않는"이벤트 핸들러를 첨부하고 div가 표시 될 때 특정 코드를 실행할 수 있습니까?

다음 의사 코드와 같은 것을 원합니다.

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

contentDiv가 실제로 표시 될 때까지 alert ( "do something") 코드가 실행되지 않아야합니다.

감사.


답변:


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
편집 :이 방법의 단점은 하나뿐입니다 : 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

여기 초보자 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

2
이것은 실제로 작동하며 레거시 브라우저를 지원할 필요가 없으므로 완벽합니다! I'br 여기에 해답의 JSFiddle 증거를 추가 : jsfiddle.net/DanAtkinson/26URF
댄 앳킨슨에게

크롬에서는 잘 작동하지만 블랙 베리 10 캐스케이드 웹뷰에서는 작동하지 않습니다 (다른 사람이 관심이 있다면;)
Guillaume Gendre

1
가시성 변경이 모니터링 대상 조상의 속성 변경으로 인해 발생하는 경우 작동하지 않는 것 같습니다.
Michael

4
Chrome 51에서는 작동하지 않는 것 같습니다. 이유는 확실하지 않습니다. 위의 코드를 실행하고 버튼을 누르면 경고가 없습니다.
Kris

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 () 메서드를 호출 할 수 없습니다.
frankadelic

11
JS는 조직 외부의 개발 팀에서 제공했습니다. 또한 "블랙 박스"의 일종이므로 가능한 경우 해당 코드를 수정하고 싶지 않습니다. 그래도 우리의 유일한 선택 일 수 있습니다.
frankadelic

항상 자신의 구현으로 js 함수를 스탬핑 할 수 있습니다. 그러나 어리석은 소리!
redsquare

11
@redsquare : show()위에서 설명한 코드 블록 이외의 여러 곳에서 호출 하면 어떻게 됩니까?
Robin Maben

1
이 예제에서는 onIsVisible"isVisible"사용이 약간 모호 하기 때문에 함수 이름을 변경해야합니다 .
브래드 존슨

27

jQuery의 Live Query 플러그인을 사용할 수 있습니다 . 다음과 같이 코드를 작성하십시오.

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

그런 다음 contentDiv가 표시 될 때마다 "뭔가하세요"라는 경고가 나타납니다!


음, 잘 작동합니다. 나는 그것에 대해 생각하고 그것을 시도하지 않고 작동하지 않을 것으로 거부했습니다. 그것을 시도해야합니다. :)
neminem

1
나를 위해 작동하지 않았다. "실시간 쿼리가 함수가 아닙니다"오류가 발생합니다. "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-이론 솔루션 당신은에 의해 분류 요소를 선택하는 기능을 쓸 수 있습니다 .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 2

또는 display:none?
Michael

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
이것은 나를 위해 완벽하게 작동했지만 함수가 show 및 hide 함수에서 체인 연결을 끊어 많은 플러그인을 중단한다는 점에 유의해야합니다. el.apply(this, arguments)이 문제를 해결하려면 앞에 반품을 추가하십시오 .
jaimerump

이것이 내가 찾던 것입니다! @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);
});

상단의 배열에 "attr"과 같은 추가하여 jQuery 함수에 재정의를 추가 할 수 있습니다.


9

Glenns ideea에 기반한 hide / show 이벤트 트리거 : show / hide를 발생시키고 하나의 이벤트에 대해 2fire를 원하지 않기 때문에 토글 제거

$(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을 확인하고 Attr도 제거해야합니까?
Andrija

5

나는이 같은 문제가 있었고 우리 사이트를 위해 그것을 해결하기 위해 jQuery 플러그인을 만들었습니다.

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

예제를 기반으로 사용하는 방법은 다음과 같습니다.

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

1
폴링은 그다지 효율적이지 않으며 많은 요소에 사용 된 경우 브라우저 속도를 크게 느리게합니다.
Cerin


4

여기에 도움이 된 것은 최근 ResizeObserver 사양 polyfill입니다 .

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

영감을 받음 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 Software

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에서 hide / show 이벤트 트리거를 변경했습니다. 내 문제는 모듈 식 응용 프로그램이 있다는 것입니다. 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;
    }
});

그런 다음 아이가 "show"또는 "hide"이벤트를 듣고 자 할 때 클래스 "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

한 가지 방법입니다.
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.