问题
I would like to be able to delay the default action of an event until some other action has been taken.
What it's for: I'm trying to build a reusable, unobtrusive way to confirm actions with a modal-type dialogue. The key wishlist item is that any Javascript handlers are attached by a script, and not written directly inline.
To make this truly reusable, I want to use it on different types of items: html links, checkboxes, and even other Javascript-driven actions. And for purely HTML elements like links or checkboxes, I want them to degrade gracefully so they're usable without Javascript turned on.
Here's how I would envision the implementation:
<a href="/somelink/" class="confirm">Some Link</a>
_________
<script>
attachEvent('a.confirm','click', confirmAction.fire)
var confirmAction = (function(){
var public = {
fire: function(e){
e.default.suspend();
this.modal();
},
modal: function(){
showmodal();
yesbutton.onclick = this.confirmed;
nobutton.onclick = this.canceled;
},
confirmed: function(){
hidemodal();
e.default.resume();
},
canceled: function(){
hidemodal();
e.default.prevent();
}
}
return public;
})()
</script>
I know about the e.preventDefault function, but that will kill the default action without giving me the ability to resume it. Obviously, the default object with the suspend, resume and prevent methods is made up to illustrate my desired end.
By the way, I'm building this using the Ext.Core library, if that helps. The library provides a good deal of normalization for handling events. But I'm really very interested in learning the general principles of this in Javascript.
回答1:
To resume, you could try saving the event and re-fire it, setting a flag that can be used to skip the handlers that call suspend() ('confirmAction.fire', in your example).
<a href="/somelink/" class="confirm">Some Link</a>
_________
<script>
function bindMethod(self, method) {
return function() {
method.apply(self, arguments);
}
}
var confirmAction = (function(){
var public = {
delayEvent: function(e) {
if (e.suspend()) {
this.rememberEvent(e);
return true;
} else {
return false;
}
},
fire: function(e){
if (this.delayEvent(e)) {
this.modal();
}
},
modal: function(){
showmodal();
yesbutton.onclick = bindMethod(this, this.confirmed);
nobutton.onclick = bindMethod(this, this.canceled);
},
confirmed: function(){
hidemodal();
this.rememberEvent().resume();
},
canceled: function(){
hidemodal();
this.forgetEvent();
},
rememberEvent: function (e) {
if (e) {
this.currEvent=e;
} else {
return this.currEvent;
}
},
forgetEvent: function () {
delete this.currEvent;
}
}
return public;
})()
// delayableEvent should be mixed in to the event class.
var delayableEvent = (function (){
return {
suspend: function() {
if (this.suspended) {
return false;
} else {
this.suspended = true;
this.preventDefault();
return true;
}
},
resume: function () {
/* rest of 'resume' is highly dependent on event implementation,
but might look like */
this.target.fireEvent(this);
}
};
})();
/* 'this' in event handlers will generally be the element the listener is registered
* on, so you need to make sure 'this' has the confirmAction methods.
*/
mixin('a.confirm', confirmAction);
attachEvent('a.confirm','click', confirmAction.fire);
</script>
This still has potential bugs, such as how it interacts with other event listeners.
来源:https://stackoverflow.com/questions/1263327/delaying-default-events-in-javascript