代码之家  ›  专栏  ›  技术社区  ›  Ross Rogers

在javascript中,如何包装onclick回调?

  •  0
  • Ross Rogers  · 技术社区  · 14 年前

    我想装饰或包装一个特定的 onclick 回调,以便在调用原始安装的回调后执行代码。

    我从这个开始,是为了用半python'ic的方式使用带有闭包的函数生成器:

    var original_onclick = node.onclick;
    function wrapper_onclick() {
        original_onclick.apply(this,arguments);
        my_code();
    }
    node.onclick = wrapper_onclick;
    

    但是,当我使用上述代码时,原始回调无法正常工作。是否传入了错误的第一个参数(上下文参数?) this . 我需要调整论点吗?是 已列入清单 arguments ?

    2 回复  |  直到 14 年前
        1
  •  3
  •   BGerrissen    14 年前

    这正是为什么许多人努力为跨浏览器事件监听找到合适的解决方案的原因。有些浏览器不能在正确的上下文中启动函数,有些浏览器不能传递事件参数,等等。使用框架要容易得多,但是如果你坚持不使用框架…

    首先,如果您有非常可怕的代码,比如:

    <a href="javascript:someFunction( this , evaledVariable );otherFn( ohDearVariable )">
    

    那么对不起,没人能帮你。

    否则…

    在任何情况下,都不能通过简单地设置 .onclick 属性,并期望它在跨浏览器中表现相同,甚至可以在您开发的浏览器中正常工作。你必须两者都用 addEventListener attachEvent 方法。

    跨浏览器事件分叉的最简单方法是:

    var addListener = function( node , event , listener ) {
    
        if ( node.addEventListener ) {
    
            node.addEventListener( event , listener , false );
    
        } else if (node.attachEvent ) {
    
            node.attachEvent( "on" + event , listener );
    
        }
    
    }
    

    删除侦听器的方法相同:

    var removeListener = function( node , event , listener ) {
    
        if ( node.addEventListener ) {
    
            node.removeEventListener( event , listener , false );
    
        } else if (node.attachEvent ) {
    
            node.detachEvent( "on" + event , listener );
    
        }
    
    }
    

    因此使用它:

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

    因此,如果要包装附加到节点的侦听器,请使用错误的onclick方法:

    var wrongOnClick = node.onclick;
    
    var listener = function( e ) {
        before();
        wrongOnClick.call( this , e );
        after();
    };
    
    addListener( node , "click" , listener );
    

    这将为包括IE在内的大多数现代浏览器提供服务,尽管要实现良好的实现,实际上需要更多的优化和内存泄漏预防代码,但不要自己编写或让他人为您编写代码,而是使用一个框架/tookit!因为当您有一个跨浏览器运行的好的实现时,您将有更多的代码膨胀,当您实际使用一个框架时…

    **补遗**

    作为黑客,我仍然建议使用addEventListener方法并保留对您的侦听器的引用。

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

    显然,这只适用于您的侦听器,如果您希望它将现有的侦听器包装在一个页面中(来自其他人的侦听器),那么就无法知道人们如何将其侦听器附加到节点上。如果他们在本文开头使用了AddEventListener/AttachEvent库或肮脏的示例,那么在没有手动编码和查找引用或手动公开引用的情况下,就无法可靠地包装它们。

        2
  •  -1
  •   Ross Rogers    14 年前

    基于Matt和Bgerrissen的帮助,以下代码对Chrome非常有用:

    var original_onclick = node.onclick;
    function wrapper_onclick(e ) {
      var ret = original_onclick(e);
      remove_story_onclicks();
      return ret;
    }
    node.onclick = wrapper_onclick;
    

    仍然不确定如何在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')
    

    哪些版画

    before
    a b c
    after