클릭 이벤트가 이미 바인딩되어 있는지 확인하는 방법-JQuery


130

클릭 이벤트를 버튼으로 바인딩하고 있습니다.

$('#myButton').bind('click',  onButtonClicked);

한 시나리오에서 이것은 여러 번 호출되기 때문에 내가 할 때 trigger여러 개의 ajax 호출을 방지하고 싶습니다.

bind이전에 묶이지 않은 경우에만 어떻게합니까?


1
남자, 나는 + 콘라드 Garus 가장 안전한 anwser (이 있다고 생각 stackoverflow.com/a/6930078/842768을 ) 당신 허용 대답을 변경하는 것이 좋습니다. 건배! 업데이트 : + Herbert Peters의 의견도 확인하십시오! 이것이 최선의 방법입니다.
giovannipds

현재 표준에 대해서는 아래 @A Morel의 답변을 참조하십시오 ( stackoverflow.com/a/50097988/1163705 ). 코딩이 적고 모든 추측 작업, 알고리즘 및 / 또는 방정식에서 기존 요소를 검색합니다.
Xandor

답변:


117

업데이트 : 2012 년 8 월 24 일 : jQuery 1.8에서는 더 이상을 사용하여 요소의 이벤트에 액세스 할 수 없습니다 .data('events'). (자세한 내용은 이 버그 를 참조하십시오.) jQuery._data(elem, 'events')문서화되지 않은 내부 데이터 구조 를 사용하여 동일한 데이터에 액세스 할 수 있으므로 100 % 안정적으로 유지되지 않습니다. 그러나 이것은 문제가되지 않아야하며, 위의 플러그인 코드의 관련 줄을 다음과 같이 변경할 수 있습니다.

var data = jQuery._data(this[0], 'events')[type];

jQuery 이벤트는이라는 데이터 객체에 저장 events되므로 다음을 검색 할 수 있습니다.

var button = $('#myButton');
if (-1 !== $.inArray(onButtonClicked, button.data('events').click)) {
    button.click(onButtonClicked);
}

물론이 코드가 한 번만 호출되도록 응용 프로그램을 구성 할 수 있다면 가장 좋습니다.


이것은 플러그인으로 캡슐화 될 수 있습니다 :

$.fn.isBound = function(type, fn) {
    var data = this.data('events')[type];

    if (data === undefined || data.length === 0) {
        return false;
    }

    return (-1 !== $.inArray(fn, data));
};

그런 다음 전화를 걸 수 있습니다.

var button = $('#myButton');
if (!button.isBound('click', onButtonClicked)) {
    button.click(onButtonClicked);
}

10
편집시 +1 이 게시물을 오늘 읽고 1.8을 사용하고 있습니다. 고마워.
Gigi2m02

2
편집 해 주셔서 감사합니다. 이것은 버튼에만 해당 <a>됩니까, 아니면 사용할 수도 있습니까? 내가 시도 할 때 jQuery._data()다음 오류 에 대해 말합니다TypeError: a is undefined
Houman

var data = jQuery._data(this[0], 'events')[type];시도 캐치에서 줄 을 감싸고 캐치에서 false를 반환합니다. [type]에 대한 호출보다이 이벤트가 [[0]에 바인딩되지 않은 경우 "정의되지 않은 또는 null 참조의 '클릭'속성을 가져올 수 없음"의 일부 변형이 발생하여 사용자가 알아야 할 사항도 분명히 알려줍니다.
Robb Vandaveer

jQuery 2.0.3에서 _data 객체가 변경되었는지 확실하지 않지만 $ .inArray를 사용할 수 없습니다. 비교하려는 함수는 "handler"라는 각 데이터 항목의 속성에 있습니다. 간단한 for 문을 사용하도록 수정하고 문자열 동등성을 검사했습니다. inArray가 가정 한 것입니다. for (var i = 0; i < data.length; i++) { if (data[i].handler.toString() === fn.toString()) { return true; } }
Robb Vandaveer 2018 년

왜 업데이트 / 편집을 맨 위로 옮기지 않겠습니까? ... 실제 정답입니다.
돈 Cheadle

179

한 가지 더 방법-CSS 버튼과 필터로 이러한 버튼을 표시하십시오.

$('#myButton:not(.bound)').addClass('bound').bind('click',  onButtonClicked);

최근에 jQuery를 버전은 대체 bind와 함께 on:

$('#myButton:not(.bound)').addClass('bound').on('click',  onButtonClicked);

4
우수한! 감사합니다 Konrad, 이것은 달콤한 자리를 명중합니다. 나는 이와 같이 우아하고 간단한 접근법을 좋아합니다. 모든 클릭 요소 (이미 클릭 이벤트 핸들러가 첨부되어 있음)가 각 요소를 비교하는 일부 큰 이벤트 버킷에서 전체 검색을 수행 할 필요가 없으므로 성능이 더 뛰어납니다. 구현에서 추가 도우미 클래스의 이름을 "click-bound"로 지정했습니다.이 옵션은 유지 관리하기 쉬운 옵션입니다. $ ( ". list-item : not (.click-bound)"). addClass ( "click-bound") ;
Nicholas Petersen

1
받아 들여진 대답에서 언급했듯이 "물론이 코드가 한 번만 호출되도록 응용 프로그램을 구성 할 수 있다면 가장 좋습니다." 이것은 그것을 달성합니다.
Jeff Dege

내 상황에서 +1, 끄기 / 켜기 및 바인드 / 바인드 해제로 여러 호출을 막았습니다. 이것이 효과가있는 솔루션이었습니다.
Jay

2
코드가 CSS 클래스의 존재를 확인하고 이미 존재하는 슬립 바인딩을 확인할 수 있기 때문에 성능에 대한 더 나은 솔루션입니다. 다른 솔루션은 더 많은 오버 헤드 (바람직하게 말할 수있는 fr4om)로 바인딩 해제 후 리 바인드 프로세스를 실행합니다.
Phil Nicholas

1
2 가지 문제. (여러 요소에 바인딩 될 수있는 플러그인에서 사용하는 경우) resize 이벤트를 창 객체에 바인딩 할 때는 작동하지 않습니다. addClass ( 'bound') 대신 data ( 'bound', 1)를 사용하는 것도 좋은 방법입니다. 이벤트를 파괴 할 때 다른 인스턴스가 의존하는 동안 그렇게 할 수 있습니다. 따라서 다른 인스턴스가 여전히 사용 중인지 확인하는 것이 좋습니다.
Herbert Peters

59

jQuery 1.7 이상을 사용하는 경우 :

당신은 off전에 전화 할 수 있습니다 on:

$('#myButton').off('click', onButtonClicked) // remove handler
              .on('click', onButtonClicked); // add handler

그렇지 않은 경우 :

첫 번째 이벤트를 바인딩 해제 할 수 있습니다.

$('#myButton').unbind('click', onButtonClicked) //remove handler
              .bind('click', onButtonClicked);  //add handler

1
이것은 멋진 솔루션이 아니지만 하나의 핸들러 바인딩을 해제하여 향상시킬 수 있습니다 .unbind('click', onButtonClicked). 매뉴얼을 보라
언젠가

16
핸들러를 추가 할 때 실제로 네임 스페이스를 지정할 수 있으며 바인딩 해제는 매우 간단 해집니다. $(sel).unbind("click.myNamespace");
Marc

@lonesomeday는 'unbind'를 사용하여 다른 것을 보여주기위한 예제입니까? .off와 효과적으로 .unbind되지 않으므로 글을 써야합니다.$('#myButton').unbind('click', onButtonClicked).bind('click', onButtonClicked);
Jim

1
@Jim 당신은 내 의견 후 3 년 동안 질문이 편집 된 것을 볼 수 있습니다! (또한 의견이 나온 직후 몇 분 안에. 내가 언급 한 내용이 더 이상 존재하지 않기 때문에 아마도 그다지 의미가없는 것 같습니다.)
lonesomeday

@lonesomeday hmmm 왜 편집되었는지 잘 모르겠습니다. 롤백해야한다고 생각하십니까?
Naftali 일명 Neal

8

내가 보는 가장 좋은 방법은 live () 또는 delegate ()를 사용하여 각 자식 요소가 아닌 부모에서 이벤트를 캡처하는 것입니다.

버튼이 #parent 요소 안에 있으면 다음을 교체 할 수 있습니다.

$('#myButton').bind('click', onButtonClicked);

으로

$('#parent').delegate('#myButton', 'click', onButtonClicked);

이 코드가 실행될 때 #myButton이 아직 없더라도.


2
더 이상 사용되지 않는 방법
dobs

8

나는 "한 번"이라는 아주 작은 플러그인을 작성했습니다. 요소를 껐다 켜십시오.

$.fn.once = function(a, b) {
    return this.each(function() {
        $(this).off(a).on(a,b);
    });
};

그리고 간단히 :

$(element).once('click', function(){
});

9
.one ()은 첫 실행 후 핸들러를 삭제합니다.
Rodolfo Jorge Nemer Nogueira

3
여기서 "한 번"은 핸들러를 한 번 연결하는 것입니다. jquery에서 "one"은 한 번만 연결하지 않고 한 번만 실행하기위한 것입니다.
Shishir Arora

1
사실 이후에 오는 것을 알고 있지만 off주어진 유형에 대한 모든 핸들러를 제거 하지는 않습니까? 관련이 없지만 동일한 항목에 별도의 클릭 핸들러가 있다면 해당 핸들러도 제거되지 않습니까?
Xandor

'keypup.test123':이 같은 모든 핸들러를 떨어 뜨리지 않도록 바로 이벤트에 네임 스페이스를 사용
SemanticZen

6

이것을 사용하지 않는 이유

unbind() 전에 bind()

$('#myButton').unbind().bind('click',  onButtonClicked);

1
$('#myButton').off().on('click', onButtonClicked);또한 나를 위해 작동합니다.
Veerakran Sereerungruangkul

나를 위해 일한다 ... gr8 솔루션
imdadhusen

아름다운. 이미 바인딩 된 버튼에 대해 완벽하게 작동합니다.
seanbreeden

3

내 버전은 다음과 같습니다.

Utils.eventBoundToFunction = function (element, eventType, fCallback) {
    if (!element || !element.data('events') || !element.data('events')[eventType] || !fCallback) {
        return false;
    }

    for (runner in element.data('events')[eventType]) {
        if (element.data('events')[eventType][runner].handler == fCallback) {
            return true;
        }

    }

    return false;
};

용법:

Utils.eventBoundToFunction(okButton, 'click', handleOkButtonFunction)

2

@ konrad-garus 답변을 기반으로하지만을 사용 합니다. 주로 스타일링에 사용해야 data한다고 생각하기 때문 class입니다.

if (!el.data("bound")) {
  el.data("bound", true);
  el.on("event", function(e) { ... });
}

2

확인 / 바인드 / 바인드 해제를 피하기 위해 접근 방식을 변경할 수 있습니다! Jquery .on ()을 사용하지 않는 이유는 무엇입니까?

Jquery 1.7, .live (), .delegate ()는 더 이상 사용되지 않으므로 .on ()을 사용하여

현재와 ​​미래 의 현재 선택기와 일치하는 모든 요소에 이벤트 핸들러를 첨부하십시오.

이는 여전히 존재하는 상위 요소에 이벤트를 첨부하고 존재 여부에 관계없이 하위 요소를 첨부 할 수 있음을 의미합니다!

다음과 같이 .on ()을 사용하는 경우 :

$('#Parent').on('click', '#myButton'  onButtonClicked);

부모에서 이벤트 클릭을 포착하고 존재하는 경우 자식 '#myButton'을 검색합니다.

따라서 자식 요소를 제거하거나 추가 할 때 이벤트 바인딩을 추가하거나 제거할지 걱정할 필요가 없습니다.


이것은 현재 표준에 대한 최고의 답변입니다. 부모를 위해 처리기를 설정하여 자식을 감시하는 기능은 잘 알려져 있지는 않지만 다소 우아한 해결책이라고 생각합니다. 나는 여러 번 사건을 겪었고 매번 총 발사 횟수가 계속 증가했습니다. 이 한 줄은 전체 트릭을 수행했으며 사용하지 않고 .off프로세스에서 관련없는 핸들러를 제거한다고 생각합니다.
Xandor


0
if ($("#btn").data('events') != undefined && $("#btn").data('events').click != undefined) {
    //do nothing as the click event is already there
} else {
    $("#btn").click(function (e) {
        alert('test');
    });
}

0

2019 년 6 월 현재 기능을 업데이트했습니다 (필요한 기능을 수행 중입니다)

$.fn.isBound = function (type) {
    var data = $._data($(this)[0], 'events');

    if (data[type] === undefined || data.length === 0) {
        return false;
    }
    return true;
};

-2

JQuery에는 솔루션있습니다 .

$( "#foo" ).one( "click", function() {
  alert( "This will be displayed only once." );
}); 

동등한:

$( "#foo" ).on( "click", function( event ) {
  alert( "This will be displayed only once." );
  $( this ).off( event );
});

1
귀하의 답변은 질문과 관련이 없습니다. 질문은 함수를 요소의 이벤트에 한 번만 바인딩하는 것에 관한 것입니다.
Michał Zalewski
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.