如何使用event.preventDefault()后触发事件
我想举办一个活动,直到我准备开火为止
$('.button').live('click', function(e){ e.preventDefault(); // do lots of stuff e.run() //this proceeds with the normal event }
有没有一个相当于上面描述的run()
函数?
不。 一旦事件被取消,它被取消。
您可以稍后重新启动事件,使用标志来确定您的自定义代码是否已经运行 – 例如(请忽略公然的命名空间污染):
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'); });
更广义的变体(避免全局命名空间污染的附加好处)可能是:
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); } }
用法:
var someThingsThatNeedToBeDoneFirst = function() { /* ... */ } // do whatever you need $('.button').on('click', onWithPrecondition(someThingsThatNeedToBeDoneFirst));
带Promise
支持的Bonus超简约jQuery插件:
(function( $ ) { $.fn.onButFirst = function(eventName, /* the name of the event to bind to, eg '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 ($.isFunction(workResult.then)) { workResult.then(successfullyCompleted); } else { successfullyCompleted(); } }); return this; }; }(jQuery));
用法:
$('.button').onButFirst('click', function(){ console.log('doing lots of work!'); }, function(){ console.log('done lots of work!'); });
接受答案的更新版本。
简短版本:
$('#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 */ } });
一个好的用例就是这样的地方,你可能有一些遗留的表单代码可以工作,但是在提交表单之前,你已经被要求增加一些类似电子邮件地址validation的function。 您可以编写一个API,然后更新您的前端代码,以便在允许表单执行传统POST之前先打这个API,而不是通过后端表单后代码进行挖掘。
要做到这一点,你可以实现类似于我在这里写的代码:
$('#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(); } });
你可以做类似的事情
$(this).unbind('click').click();
覆盖属性isDefaultPrevented
像这样防止:
$('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); }
恕我直言,这是完全相同的数据重新触发事件的最完整的方式。
可以使用event
currentTarget
。 示例显示如何进行表单提交。 同样,你可以从onclick
属性等获得function
$('form').on('submit', function(event) { event.preventDefault(); // code event.currentTarget.submit(); });
只是不要执行e.preventDefault();
,或者有条件地执行。
当原始的事件动作发生时 ,你当然不能改变。
如果你想在一段时间之后“重新创build”原始的UI事件(比如,在AJAX请求的callback中),那么你只需要用其他方式来伪造它(就像在vzwick的答案中一样)质疑这种方法的可用性。
我使用的方法是这样的:
$('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 });
只要“很多东西”没有进行asynchronous操作,这绝对是不必要的 – 事件会按顺序调用每个处理程序,所以如果父元素上的onklick事件会在onclik-孩子的事件已经完全处理了。 javascript在这里并没有做一些“multithreading”,使得“停止”事件处理成为必需。 结论:“暂停”一个事件只是为了恢复它在同一个处理程序没有任何意义。
如果“很多东西” 是asynchronous的,这也是没有意义的,因为它阻止asynchronous的事情做他们应该做的事(asynchronous的东西),让他们像一切顺序(我们回到我的第一段)
另一个解决scheme是在事件监听器中使用window.setTimeout ,并在事件过程结束后执行代码。 就像是…
window.setTimeout(function() { // do your thing }, 0);
因为我不在乎等待,所以我用了0 。
如果您正在使用锚标签,接受的解决scheme将无法正常工作。 在这种情况下,您将无法在调用e.preventDefault()
之后再次单击该链接。 那是因为jQuery生成的点击事件只是在本地浏览器事件的顶层。 所以触发一个锚点标签上的“点击”事件不会跟随链接。 相反,你可以使用像jquery-simulate这样的库,它可以让你启动本地浏览器事件。
关于这方面的更多细节可以在这个链接中find