In javascript, how can I wrapper an onclick callback?
I want to decorate or wrapper a specific onclick
callback such tha开发者_如何学JAVAt my code is executed after the original installed callback is called.
I started with this in order to do it in a semi-python'ic way using function generator with closure:
var original_onclick = node.onclick;
function wrapper_onclick() {
original_onclick.apply(this,arguments);
my_code();
}
node.onclick = wrapper_onclick;
However, when I use the above code, the original callbacks aren't working properly. Am I passing in the wrong first parameter (context parameter?) this
. Do I need to tweak the arguments? Is this
already in list arguments
?
This is exactly why lots of people worked to find a proper solution for cross browser event listening. Some browsers don't fire the function in the right context, some browsers don't pass the event argument and so on. It's a lot easier to use a framework, but if you insist on using no frameworks...
First if you have really horrible code like:
<a href="javascript:someFunction( this , evaledVariable );otherFn( ohDearVariable )">
Then sorry, no one can help you.
Otherwise...
In any case, you can't attach events directly to a node by simply setting the .onclick
attribute and expect it to behave equally cross browser or even work properly in the browser you're developing with. You must use both addEventListener
and attachEvent
methods.
The most simplest way of forking for cross browser events is:
var addListener = function( node , event , listener ) {
if ( node.addEventListener ) {
node.addEventListener( event , listener , false );
} else if (node.attachEvent ) {
node.attachEvent( "on" + event , listener );
}
}
Same for removing listeners:
var removeListener = function( node , event , listener ) {
if ( node.addEventListener ) {
node.removeEventListener( event , listener , false );
} else if (node.attachEvent ) {
node.detachEvent( "on" + event , listener );
}
}
And use it thus:
var nodeListener = function( e ) {
alert(e.target);
// run once for demo
removeListener( node , "click" , nodeListener );
}
// notice we omit the "on" part.
addListener( node , "click" , nodeListener );
So if you want to wrap listeners appended to node the WRONG onclick way:
var wrongOnClick = node.onclick;
var listener = function( e ) {
before();
wrongOnClick.call( this , e );
after();
};
addListener( node , "click" , listener );
This will serve most modern browsers including IE, though actually a lot more optimalisation and memory leak prevention code is needed for a good implementation, but instead of writing this code yourself or having others do it for you, use a framework/tookit! Because by the time you have a good implementation running that works cross browser, you will have more code bloat then when you actually used a framework...
** Addendum **
As a hack, I still suggest to use the addEventListener method and keep references to your listeners.
var aListener = function( e ) { }
node.addEventListener( "click" , aListener , false );
var wrappedListener = function ( e ) {
before( e );
aListener( e );
after( e );
}
node.removeEventListener( "click" , aListener , false );
node.addEventListener( "click" , wrappedListener , false );
This obviously only works with your listeners, if you want it to wrap existing listeners in a page (listeners from others), then there's simply no way of knowing how people appended their listeners to nodes. If they used addEventListener/attachEvent libraries or the dirty example in the beginning of this post, you simply cannot reliably wrap them without manual coding and looking up the references or manually exposing them.
Based on help from Matt and BGerrissen, the following code works great for chrome:
var original_onclick = node.onclick;
function wrapper_onclick(e ) {
var ret = original_onclick(e);
remove_story_onclicks();
return ret;
}
node.onclick = wrapper_onclick;
Still not exactly sure how to do a bulletproof wrapper like the following in python:
def wrappee(foo,bar,baz):
print foo,bar,baz
def wrapper(*args,**kwargs):
print 'before'
wrappee(*args,**kwargs)
print 'after'
wrapper('a','b','c')
which prints
before
a b c
after
精彩评论