Cách kích hoạt sự kiện sau khi sử dụng event.preventDefault ()


155

Tôi muốn tổ chức một sự kiện cho đến khi tôi sẵn sàng khai hỏa

$('.button').live('click', function(e){

   e.preventDefault(); 

   // do lots of stuff

   e.run() //this proceeds with the normal event    

}

Có tương đương với run()chức năng được mô tả ở trên?


Hành vi mặc định chỉ xảy ra sau khi xử lý của bạn trở lại. Sẽ không có ý nghĩa gì để ngăn chặn hành vi đó chỉ cho phép nó sau này trong trình xử lý của bạn.
Frédéric Hamidi

7
@ Frédéric Hamidi Thật không may, công cụ async ($ .ajax, cuộc gọi lại, v.v.) sẽ cho phép hành vi mặc định xảy ra.
vzwick

Câu trả lời:


164

Không. Một khi sự kiện đã bị hủy bỏ, nó sẽ bị hủy bỏ.

Mặc dù vậy, bạn có thể kích hoạt lại sự kiện sau đó bằng cách sử dụng cờ để xác định xem mã tùy chỉnh của bạn đã chạy hay chưa - chẳng hạn như điều này (vui lòng bỏ qua ô nhiễm không gian tên trắng trợn):

var lots_of_stuff_already_done = false;

$('.button').on('click', function(e) {
    if (lots_of_stuff_already_done) {
        lots_of_stuff_already_done = false; // reset flag
        return; // let the event bubble away
    }

    e.preventDefault();

    // do lots of stuff

    lots_of_stuff_already_done = true; // set flag
    $(this).trigger('click');
});

Một biến thể tổng quát hơn (với lợi ích bổ sung là tránh ô nhiễm không gian tên toàn cầu) có thể là:

function onWithPrecondition(callback) {
    var isDone = false;

    return function(e) {
        if (isDone === true)
        {
            isDone = false;
            return;
        }

        e.preventDefault();

        callback.apply(this, arguments);

        isDone = true;
        $(this).trigger(e.type);
    }
}

Sử dụng:

var someThingsThatNeedToBeDoneFirst = function() { /* ... */ } // do whatever you need
$('.button').on('click', onWithPrecondition(someThingsThatNeedToBeDoneFirst));

Phần thưởng jQuery siêu tối giản có Promisehỗ trợ:

(function( $ ) {
    $.fn.onButFirst = function(eventName,         /* the name of the event to bind to, e.g. 'click' */
                               workToBeDoneFirst, /* callback that must complete before the event is re-fired */
                               workDoneCallback   /* optional callback to execute before the event is left to bubble away */) {
        var isDone = false;

        this.on(eventName, function(e) {
            if (isDone === true) {
                isDone = false;
                workDoneCallback && workDoneCallback.apply(this, arguments);
                return;
            }

            e.preventDefault();

            // capture target to re-fire event at
            var $target = $(this);

            // set up callback for when workToBeDoneFirst has completed
            var successfullyCompleted = function() {
                isDone = true;
                $target.trigger(e.type);
            };

            // execute workToBeDoneFirst callback
            var workResult = workToBeDoneFirst.apply(this, arguments);

            // check if workToBeDoneFirst returned a promise
            if (workResult && $.isFunction(workResult.then))
            {
                workResult.then(successfullyCompleted);
            }
            else
            {
                successfullyCompleted();
            }
        });

        return this;
    };
}(jQuery));

Sử dụng:

$('.button').onButFirst('click',
    function(){
        console.log('doing lots of work!');
    },
    function(){
        console.log('done lots of work!');
    });

4
.live bị lỗi. Sử dụng .on được sử dụng trong ví dụ @Cory Danielson bên dưới.
nwolyorms

Đây là một lần nữa vào bên trong .click và cuối cùng tôi thấy "quá nhiều đệ quy"
Himanshu Pathak

5
@HimanshuPathak - có lẽ bạn đã quên đặt lots_of_stuff_already_done = true;cờ - nếu không thì không có cách nào để chức năng tiếp tục đệ quy.
vzwick

73

Một phiên bản gần đây hơn của câu trả lời được chấp nhận.

Phiên bản ngắn gọn:

$('#form').on('submit', function(e, options) {
    options = options || {};

    if ( !options.lots_of_stuff_done ) {
        e.preventDefault();
        $.ajax({
            /* do lots of stuff */
        }).then(function() {
            // retrigger the submit event with lots_of_stuff_done set to true
            $(e.currentTarget).trigger('submit', { 'lots_of_stuff_done': true });
        });
    } else {
        /* allow default behavior to happen */
    }

});



Trường hợp sử dụng tốt cho một cái gì đó như thế này là nơi bạn có thể có một số mã biểu mẫu kế thừa hoạt động, nhưng bạn đã được yêu cầu nâng cao biểu mẫu bằng cách thêm một cái gì đó như xác thực địa chỉ email trước khi gửi biểu mẫu. Thay vì đào qua mã bài đăng của biểu mẫu mặt sau, bạn có thể viết API và sau đó cập nhật mã mặt trước của mình để truy cập API đó trước khi cho phép biểu mẫu thực hiện POST truyền thống.

Để làm điều đó, bạn có thể triển khai mã tương tự như những gì tôi đã viết ở đây:

$('#signup_form').on('submit', function(e, options) {
    options = options || {};

    if ( !options.email_check_complete ) {

        e.preventDefault(); // Prevent form from submitting.
        $.ajax({
            url: '/api/check_email'
            type: 'get',
            contentType: 'application/json',
            data: { 
                'email_address': $('email').val() 
            }
        })
        .then(function() {
            // e.type === 'submit', if you want this to be more dynamic
            $(e.currentTarget).trigger(e.type, { 'email_check_complete': true });
        })
        .fail(function() {
            alert('Email address is not valid. Please fix and try again.');
        })

    } else {

        /**
             Do traditional <form> post.
             This code will be hit on the second pass through this handler because
             the 'email_check_complete' option was passed in with the event.
         */

        $('#notifications').html('Saving your personal settings...').fadeIn();

    }

});

1
"Thay vì đào qua mã bài viết ở mặt sau" ... Thực tế bạn phải làm điều đó bằng mọi cách, bạn không thể chỉ dựa vào xác thực phía máy khách.
Diego V

18

Bạn có thể làm một cái gì đó như

$(this).unbind('click').click();

Đây là một giải pháp thực sự tốt - nhưng dường như không hoạt động trên IE10 / 11; (
JonB

47
Tại sao bạn kiểm duyệt từ "đau"?
Sean Kendle

Bạn đã kích hoạt nhấp chuột nhưng bạn có thể nhấp lại không?
Tom Anderson

16

Ghi đè tài sản isDefaultPreventednhư thế này:

$('a').click(function(evt){
  evt.preventDefault();

  // in async handler (ajax/timer) do these actions:
  setTimeout(function(){
    // override prevented flag to prevent jquery from discarding event
    evt.isDefaultPrevented = function(){ return false; }
    // retrigger with the exactly same event data
    $(this).trigger(evt);
  }, 1000);
}

IMHO, đây là cách hoàn chỉnh nhất để truy xuất sự kiện với cùng một dữ liệu.


ekhông định nghĩa được. nên evt.preventDefault(). Tôi đã cố chỉnh sửa, nhưng các chỉnh sửa của tôi phải có> 6 ký tự và tôi chỉ cần thêm 2 :(
kevnk

3
@kevnk, tôi thường bao gồm một mô tả ngắn gọn về chỉnh sửa dưới dạng nhận xét dòng. Điều này sẽ làm tăng số lượng nhân vật được gửi.
recurse

không biết tại sao câu trả lời này không được nêu lên nhiều hơn, điều này thực sự hữu ích. Làm việc với tuyên truyền dừng quá với event.isPropagationStopped = function(){ return false; };. Tôi cũng đã thêm một thuộc tính tùy chỉnh cho sự kiện để tôi có thể phát hiện trong trình xử lý nếu kiểm tra ngăn chặn hành động được thực hiện để nó không được thực hiện lại. Tuyệt quá!
Kaddath

Tôi đã sử dụng cho Bootstrap 4 Tab, Nó hoạt động rất tốt. Cảm ơn nhiều. $ ('# v-thuốc-tab a'). on ('click', function (e) {e.preventDefault (); setTimeout (function () {e.isDefaultPrevented = function () {return false;} $ ( '# v-thuốc-home-tab'). on ('shows.bs.tab', function () {$ ('. mainDashboard'). show (); $ ('# changePlans'). Hide (); });}, 1000); $ (này) .tab ('hiển thị');});
Surya R Praveen

8

Có thể sử dụng currentTargetcác event. Ví dụ cho thấy làm thế nào để tiến hành với hình thức gửi. Tương tự như vậy, bạn có thể có được chức năng từ onclickthuộc tính, vv

$('form').on('submit', function(event) {
  event.preventDefault();

  // code

  event.currentTarget.submit();
});

gửi không phải là một chức năng hợp lệ
Devaffair

nếu bạn gọi submit()trên cùng một phần tử, bạn sẽ không trả về mã `` $ ('mẫu'). trên ('submit') và làm lại nhiều lần chứ?
Fanie Void

7

Chỉ không thực hiện e.preventDefault(); , hoặc thực hiện nó có điều kiện.

Bạn chắc chắn không thể thay đổi khi hành động sự kiện ban đầu xảy ra.

Nếu bạn muốn "tạo lại" sự kiện UI ban đầu một thời gian sau (giả sử, trong cuộc gọi lại cho yêu cầu AJAX) thì bạn sẽ phải giả mạo nó theo một cách khác (như trong câu trả lời của vzwick) ... mặc dù tôi đặt câu hỏi về tính khả dụng của cách tiếp cận như vậy



3

miễn là "nhiều thứ" không làm điều gì đó không đồng bộ thì điều này hoàn toàn không cần thiết - sự kiện sẽ gọi mọi người xử lý theo cách của anh ta, vì vậy nếu có sự kiện onklick trên phần tử cha mẹ thì điều này sẽ phát sinh sau khi onclik- sự kiện của trẻ đã xử lý hoàn toàn. javascript không thực hiện một số loại "đa luồng" ở đây làm cho "dừng" xử lý sự kiện cần thiết. kết luận: "tạm dừng" một sự kiện chỉ để tiếp tục nó trong cùng một trình xử lý không có ý nghĩa gì.

nếu "nhiều thứ" một thứ gì đó không đồng bộ thì điều này cũng không có ý nghĩa gì vì nó ngăn cản những thứ không đồng nhất làm những gì họ nên làm (những thứ không đồng nhất) và làm cho chúng trở nên giống như mọi thứ đang diễn ra (trong đó chúng ta quay lại đoạn đầu tiên của mình )


Quá trình ở giữa là không đồng bộ, tôi muốn kích hoạt kết quả trong cuộc gọi lại ajax ...
Mazatec

1
nếu bạn phải đợi một yêu cầu ajax, hãy biến nó thành đồng bộ (đối với jquery, có async-fag: api.jquery.com/jQuery.ajax ) ... nhưng thực hiện yêu cầu ajax đồng bộ là một ý tưởng tồi trong hầu hết mọi trường hợp, vì vậy sẽ tốt hơn nếu tìm một giải pháp khác
oezi

3

Cách tiếp cận tôi sử dụng là:

$('a').on('click', function(event){
    if (yourCondition === true) { //Put here the condition you want
        event.preventDefault(); // Here triggering stops
        // Here you can put code relevant when event stops;
        return;
    }
    // Here your event works as expected and continue triggering
    // Here you can put code you want before triggering
});

2

Giải pháp được chấp nhận sẽ không hoạt động trong trường hợp bạn đang làm việc với thẻ neo. Trong trường hợp này, bạn sẽ không thể nhấp lại vào liên kết sau khi gọi e.preventDefault(). Đó là bởi vì sự kiện nhấp chuột được tạo bởi jQuery chỉ là lớp trên đầu các sự kiện trình duyệt gốc. Vì vậy, việc kích hoạt sự kiện 'nhấp chuột' trên thẻ neo sẽ không theo liên kết. Thay vào đó, bạn có thể sử dụng một thư viện như mô phỏng jquery cho phép bạn khởi chạy các sự kiện trình duyệt riêng.

Thông tin chi tiết về điều này có thể được tìm thấy trong liên kết này


1

Một giải pháp khác là sử dụng window.setTimeout trong trình nghe sự kiện và thực thi mã sau khi quá trình của sự kiện kết thúc. Cái gì đó như...

window.setTimeout(function() {
  // do your thing
}, 0);

Tôi sử dụng 0 trong khoảng thời gian vì tôi không quan tâm đến việc chờ đợi.


1

Tôi biết chủ đề này đã cũ nhưng tôi nghĩ tôi có thể đóng góp. Bạn có thể kích hoạt hành vi mặc định của một sự kiện trên một yếu tố cụ thể bất cứ lúc nào trong chức năng xử lý của bạn nếu bạn đã biết hành vi đó. Ví dụ: khi bạn kích hoạt sự kiện nhấp chuột vào nút đặt lại, bạn thực sự gọi chức năng đặt lại ở dạng gần nhất là hành vi mặc định. Trong hàm xử lý của bạn, sau khi sử dụng hàm notifyDefault, bạn có thể nhớ lại hành vi mặc định bằng cách gọi hàm đặt lại ở dạng gần nhất ở bất cứ đâu trong mã trình xử lý của bạn.


0

Nếu ví dụ này có thể giúp ích, hãy thêm "popin xác nhận tùy chỉnh" vào một số liên kết (tôi giữ mã "$ .ui.Modal.conf Confirm", đó chỉ là một ví dụ cho cuộc gọi lại thực hiện hành động ban đầu):

//Register "custom confirm popin" on click on specific links
$(document).on(
    "click", 
    "A.confirm", 
    function(event){
        //prevent default click action
        event.preventDefault();
        //show "custom confirm popin"
        $.ui.Modal.confirm(
            //popin text
            "Do you confirm ?", 
            //action on click 'ok'
            function() {
                //Unregister handler (prevent loop)
                $(document).off("click", "A.confirm");
                //Do default click action
                $(event.target)[0].click();
            }
        );
    }
);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.