Event.preventDefault () kullandıktan sonra bir olay nasıl tetiklenir


156

Bir olayı kovmaya hazır olana kadar tutmak istiyorum örn.

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

   e.preventDefault(); 

   // do lots of stuff

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

}

run()Yukarıda açıklanan işleve eşdeğer mi?


Varsayılan davranış yalnızca işleyiciniz döndükten sonra gerçekleşir. Bu davranışın yalnızca işleyicinizde daha sonra izin vermesini önlemek çok az mantıklıdır.
Frédéric Hamidi

7
@ FrédéricHamidi Maalesef, zaman uyumsuz şeyler ($ .ajax, geri aramalar vb.) Varsayılan davranışın gerçekleşmesine izin verecektir.
vzwick

Yanıtlar:


165

Hayır! Etkinlik iptal edildikten sonra iptal edilir.

Özel kodunuzun zaten çalışıp çalışmadığını belirlemek için bir bayrak kullanarak etkinliği daha sonra yeniden başlatabilirsiniz - bunun gibi (lütfen açık ad alanı kirliliğini dikkate almayı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');
});

Daha genel bir varyant (küresel ad alanı kirliliğinden kaçınmanın ek yararı ile) şunlar olabilir:

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

Kullanımı:

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

PromiseDestekli süper minimalist jQuery eklentisi :

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

Kullanımı:

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

4
.live karmaşıktır. Aşağıdaki @Cory Danielson örneğinde kullanılan .on kullanın.
nwolybug

Bu tekrar içeri giriyor. Tıklayın ve sonunda "çok fazla özyineleme" görüyorum
Himanshu Pathak

5
@HimanshuPathak - büyük olasılıkla lots_of_stuff_already_done = true;bayrağı ayarlamayı unuttunuz - aksi takdirde fonksiyonun tekrar etmesini sağlamanın bir yolu yoktur.
vzwick

73

Kabul edilen cevabın daha yeni bir versiyonu.

Kısa versiyon:

$('#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 */
    }

});



Böyle bir şey için iyi bir kullanım örneği, çalışan bazı eski form koduna sahip olabileceğiniz yerdir, ancak formu göndermeden önce e-posta adresi doğrulaması gibi bir şey ekleyerek formu geliştirmeniz istenir. Arka uç form posta kodunu kazmak yerine, bir API yazabilir ve ardından formun geleneksel POST yapmasına izin vermeden önce bu API'yı vurmak için ön uç kodunuzu güncelleyebilirsiniz.

Bunu yapmak için, burada yazdıklarıma benzer bir kod uygulayabilirsiniz:

$('#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
"Arka uç form posta kodunu kazmak yerine" ... Aslında bunu yine de yapmanız gerekir, yalnızca istemci tarafı doğrulamasına güvenemezsiniz.
Diego V

18

Gibi bir şey yapabilirsin

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

Bu gerçekten güzel bir çözüm - ama IE10 / 11'de çalışmıyor gibi görünüyor; (
JonB

47
Neden "acı" kelimesini sansürlediniz?
Sean Kendle

Tıklamayı tetiklediniz, ancak tekrar tıklayabilir misiniz?
Tom Anderson

16

Özelliği isDefaultPreventedşu şekilde geçersiz kıl :

$('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, olayı tam olarak aynı verilerle almanın en eksiksiz yoludur.


etanımsız. olmalı evt.preventDefault(). Düzenlemeye çalıştım, ancak düzenlemelerimin 6 karakterden fazla olması gerekiyordu ve sadece 2 :(
kevnk

3
@kevnk, genellikle düzenlemenin kısa bir açıklamasını satır açıklaması şeklinde eklerim. Bu, gönderilen karakter sayısını artırmalıdır.
recurse

bu cevabın neden daha fazla değerlendirilmediğini bilmiyorum, bu gerçekten yararlı. İle yayılım durur ile çalışır event.isPropagationStopped = function(){ return false; };. Ayrıca, eylemi engelleyen denetimin tekrar yapılıp yapılmadığını kontrol eden işleyicide algılayabilmem için özel bir özellik ekledim. Harika!
Kaddath

Bootstrap 4 Tabs için kullandım, mükemmel çalıştı. Çok teşekkürler. $ ('# v-haplar-sekmesi a'). üzerinde ('klik', işlev (e) {e.preventDefault (); setTimeout (function () {e.isDefaultPrevented = function () {return false;} $ ( '# v-pills-home-sekmesi'). });}, 1000); $ (bu) .tab ('göster');});
Surya R Praveen

8

Kullanmak mümkündür currentTargetarasında event. Örnek form gönderme işlemine nasıl devam edileceğini gösterir. Aynı şekilde onclicközellik vb.

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

  // code

  event.currentTarget.submit();
});

gönderme geçerli bir işlev değil
Devaffair

submit()aynı öğeyi çağırırsanız , `` $ ('form').
Fanie

7

Sadece yapma e.preventDefault(); ya da koşullu gerçekleştirin.

Kesinlikle ne zaman değiştiremezsin orijinal olay eylemi gerçekleşir.

Orijinal UI etkinliğini bir süre sonra "yeniden oluşturmak" istiyorsanız (diyelim ki, AJAX isteği için geri aramada), başka bir şekilde (vzwick'in cevabında olduğu gibi) taklit etmeniz gerekir ... böyle bir yaklaşımın kullanılabilirliğini sorgular.



3

"çok fazla" eşzamansız bir şey yapmadığı sürece bu kesinlikle gereksizdir - olay her işleyiciyi sırayla çağırır, bu nedenle bir üst öğede bir onklick olayı varsa, bu onclik- olay tamamen işledi. javascript burada olay işlemeyi "durdurmayı" zorunlu kılan bir tür "çoklu iş parçacığı" yapmaz. Sonuç: Bir olayı yalnızca aynı işleyicide devam ettirmek için "duraklatmak" hiçbir anlam ifade etmiyor.

"sürü" halinde olduğunu , bu asenkron bir şey bu yaptıkları (Eşzamansız şeyler) ve her şey sırayla gibi biz ilk paragrafa geri geldiği (onları bahave yapmalıdır ne yapacağını Eşzamansız şeyler engeller olarak da mantıklı değil )


Ortadaki süreç asenkron, ben ajax geri arama sonucu ateş etmek istiyorum ...
Mazatec

1
bir ajax isteği beklemek zorunda kalırsanız, eşzamanlı hale getirin (jquery için async-fag: api.jquery.com/jQuery.ajax ) ... ama eşzamanlı ajax-isteği yapmak neredeyse her durumda kötü bir fikirdir, farklı bir çözüm bulmak daha iyi olur.
oezi

3

Kullandığım yaklaşım şudur:

$('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

Bir çapa etiketi ile çalışmanız durumunda kabul edilen çözüm çalışmaz. Bu durumda, aradıktan sonra bağlantıyı tekrar tıklayamazsınız e.preventDefault(). Çünkü jQuery tarafından oluşturulan tıklama olayı sadece yerel tarayıcı olaylarının üstünde bir katman. Dolayısıyla, bir tutturma etiketinde 'tıklama' etkinliğini tetiklemek bağlantıyı izlemez. Bunun yerine jquery-simulate gibi bir kütüphane kullanabilirsiniz. , yerel tarayıcı etkinliklerini başlatmanıza izin veren .

Bununla ilgili daha fazla ayrıntı bu bağlantıda bulunabilir


1

Başka bir çözüm, olay dinleyicisinde window.setTimeout kullanmak ve etkinliğin işlemi bittikten sonra kodu çalıştırmaktır. Gibi bir şey...

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

Bekleme umurumda olmadığından dönem için 0 kullanıyorum .


1

Bu konunun eski olduğunu biliyorum ama katkıda bulunabileceğimi düşünüyorum. Bu davranışı zaten biliyorsanız, belirli bir öğedeki bir olayın varsayılan davranışını işleyici işlevinizde istediğiniz zaman tetikleyebilirsiniz. Örneğin, sıfırlama düğmesindeki click olayını tetiklediğinizde, aslında en yakın formdaki sıfırlama işlevini varsayılan davranış olarak çağırırsınız. İşleyici işlevinizde, cancelDefault işlevini kullandıktan sonra, işleyici kodunuzdaki herhangi bir yere en yakın formdaki sıfırlama işlevini çağırarak varsayılan davranışı geri çağırabilirsiniz.


0

Bu örnek yardımcı olabilir, bazı bağlantılara "özel onay popin" ekler ("$ .ui.Modal.confirm" kodunu saklıyorum, sadece orijinal eylemi yürüten geri arama için bir örnek):

//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();
            }
        );
    }
);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.