[javascript] jQuery와 바인딩 된 이벤트를 주문하는 방법

4 개의 스크립트 블록을 포함 할 수있는 페이지가있는 웹 응용 프로그램이 있다고 가정 해 보겠습니다. 내가 작성한 스크립트는 해당 블록 중 하나에서 발견 될 수 있지만 컨트롤러가 처리하는 스크립트는 알 수 없습니다.

일부 onclick이벤트를 버튼에 바인딩 하지만 때로는 예상하지 못한 순서로 실행되는 것을 알았습니다.

주문을 보장 할 수있는 방법이 있습니까, 아니면 과거에이 문제를 어떻게 처리 했습니까?



답변

나는 이런 종류의 과정을 일반화하기 위해 여러 해 동안 노력했지만, 제 경우에는 체인에서 첫 번째 이벤트 리스너의 순서에만 관심이있었습니다.

사용중인 경우 다음은 항상 다른 이벤트보다 먼저 트리거되는 이벤트 리스너를 바인딩하는 jQuery 플러그인입니다.

** jQuery 변경 사항과 함께 업데이트 된 인라인 (Toskan 덕분에) **

(function($) {
    $.fn.bindFirst = function(/*String*/ eventType, /*[Object])*/ eventData, /*Function*/ handler) {
        var indexOfDot = eventType.indexOf(".");
        var eventNameSpace = indexOfDot > 0 ? eventType.substring(indexOfDot) : "";

        eventType = indexOfDot > 0 ? eventType.substring(0, indexOfDot) : eventType;
        handler = handler == undefined ? eventData : handler;
        eventData = typeof eventData == "function" ? {} : eventData;

        return this.each(function() {
            var $this = $(this);
            var currentAttrListener = this["on" + eventType];

            if (currentAttrListener) {
                $this.bind(eventType, function(e) {
                    return currentAttrListener(e.originalEvent);
                });

                this["on" + eventType] = null;
            }

            $this.bind(eventType + eventNameSpace, eventData, handler);

            var allEvents = $this.data("events") || $._data($this[0], "events");
            var typeEvents = allEvents[eventType];
            var newEvent = typeEvents.pop();
            typeEvents.unshift(newEvent);
        });
    };
})(jQuery);

참고 사항 :

  • 이것은 완전히 테스트되지 않았습니다.
  • 변경되지 않는 jQuery 프레임 워크의 내부에 의존합니다 (1.5.2로만 테스트).
  • 소스 요소의 속성이나 jQuery bind () 및 기타 관련 함수를 사용하지 않고 다른 방식으로 바인딩 된 이벤트 리스너 전에 반드시 트리거되지는 않습니다.

답변

순서가 중요한 경우 다른 콜백에 의해 해당 이벤트가 트리거 될 때 자체 이벤트를 생성하고 콜백을 시작하여 바인딩 할 수 있습니다.

$('#mydiv').click(function(e) {
    // maniplate #mydiv ...
    $('#mydiv').trigger('mydiv-manipulated');
});

$('#mydiv').bind('mydiv-manipulated', function(e) {
    // do more stuff now that #mydiv has been manipulated
    return;
});

적어도 그런 것.


답변

모든 콜백이 항상 존재하고 서로 의존하는 것에 만족한다면 Dowski의 방법이 좋습니다.

콜백이 서로 독립적이기를 원한다면 버블 링을 활용하고 후속 이벤트를 부모 요소의 대리자로 첨부 할 수 있습니다. 부모 요소의 처리기는 요소의 처리기 다음에 트리거되어 문서까지 계속됩니다. 이것은 당신이 사용할 수있는 아주 좋은 event.stopPropagation(), event.preventDefault()등 핸들러를 생략하고 취소 작업을 취소합니다 취소합니다.

$( '#mybutton' ).click( function(e) {
    // Do stuff first
} );

$( '#mybutton' ).click( function(e) {
    // Do other stuff first
} );

$( document ).delegate( '#mybutton', 'click', function(e) {
    // Do stuff last
} );

또는이 방법이 마음에 들지 않으면 Nick Leaches bindLast 플러그인을 사용하여 이벤트가 마지막으로 바인딩되도록 할 수 있습니다 : https://github.com/nickyleach/jQuery.bindLast .

또는 jQuery 1.5를 사용하는 경우 새로운 Deferred 객체로 영리한 작업을 수행 할 수도 있습니다.


답변

바운드 콜백이 호출되는 순서는 각 jQuery 객체의 이벤트 데이터에 의해 관리됩니다. 해당 데이터를 직접보고 조작 할 수있는 함수 (내가 아는 것)는 없으며 bind () 및 unbind () (또는 동등한 도우미 함수) 만 사용할 수 있습니다.

Dowski의 방법이 가장 좋습니다. “실제”이벤트에 바인딩 된 “첫 번째”콜백을 사용하여 정렬 된 일련의 사용자 지정 이벤트에 바인딩하도록 다양한 바인딩 된 콜백을 수정해야합니다. 그렇게하면 순서에 관계없이 시퀀스가 ​​올바른 방식으로 실행됩니다.

내가 볼 수있는 유일한 대안은 실제로 생각하고 싶지 않은 것입니다. 함수의 바인딩 구문이 바인딩되기 전에 알고 있다면 해당 함수를 모두 바인딩 해제 한 다음 다시 바인딩하십시오. 적절한 순서대로. 이제 코드가 중복되었으므로 문제가 발생했습니다.

jQuery를 사용하여 객체의 이벤트 데이터에서 바운드 이벤트의 순서를 간단하게 변경할 수는 있지만 가능하지 않은 jQuery 코어에 연결하는 코드를 작성하지 않고도 멋질 것입니다. 그리고 내가 생각하지 않은 것을 허용하면 의미가있을 수 있으므로 의도적으로 누락되었을 수 있습니다.


답변

jQuery 유니버스에서는 버전 1.8과 다르게 구현해야합니다. 다음 릴리스 노트는 jQuery 블로그에 있습니다.

.data ( “events”) : jQuery는 이벤트 관련 데이터를 각 요소의 (기다리는) 이벤트라는 데이터 객체에 저장합니다. 이것은 내부 데이터 구조이므로 1.8에서는 사용자 데이터 네임 스페이스에서 제거되므로 동일한 이름의 항목과 충돌하지 않습니다. jQuery의 이벤트 데이터는 여전히 jQuery._data (element, “events”)를 통해 액세스 할 수 있습니다

jQuery 유니버스에서 처리기가 실행될 순서를 완전히 제어 할 수 있습니다 . Ricoo는 이것을 위에서 지적합니다. 그의 대답이 그에게 많은 사랑을 얻은 것처럼 보이지는 않지만이 기술은 매우 유용합니다. 예를 들어, 라이브러리 위젯에서 일부 핸들러에 앞서 자체 핸들러를 실행해야하거나 조건부로 위젯 핸들러에 대한 호출을 취소 할 수있는 권한이 있어야하는 경우를 고려하십시오.

$("button").click(function(e){
    if(bSomeConditional)
       e.stopImmediatePropagation();//Don't execute the widget's handler
}).each(function () {
    var aClickListeners = $._data(this, "events").click;
    aClickListeners.reverse();
});


답변

핸들러를 정상적으로 바인드하고 다음을 실행하십시오.

element.data('events').action.reverse();

예를 들어 :

$('#mydiv').data('events').click.reverse();


답변

function bindFirst(owner, event, handler) {
    owner.unbind(event, handler);
    owner.bind(event, handler);

    var events = owner.data('events')[event];
    events.unshift(events.pop());

    owner.data('events')[event] = events;
}