代码之家  ›  专栏  ›  技术社区  ›  Steven

扩展库时追加jQuery回调函数

  •  3
  • Steven  · 技术社区  · 14 年前

    短版本: 我正在扩展一个jQuery对象函数,该函数打算接受0-3个参数,并将它们作为第二个到第四个参数传递到 jQuery.animate . 除此之外,我想隔离回调并在它的末尾放入另一个函数调用。


    我以普通的方式扩展jQuery库,通过 jQuery.fn.newfunction = ...

    jQuery.fn.expand_to_parent_container = function() {
      var args = Array.prototype.slice.call(arguments);
    
      return this.each(function(){
        var parent = $(this).parent();
        parent.inner_width = parent.innerWidth();
    
        var inner_outer_differential = $(this).outerWidth(true) - $(this).width();
    
        // store original width for reversion later
        $(this).data('original_width', $(this).width());
    
        args.unshift({ width: parent.inner_width - inner_outer_differential });
    
        $.fn.animate.apply($(this), args );
      });
    }
    

    很简单。我用的是 arguments properties .animate ( API here ). 因此,目的是允许 .expand_to_parent_container 接受论点 duration, easing, callback jQuery.speed 负责解决这个问题,但我不想直接使用它/篡改它,因为它看起来不像其他jQuery函数那样具有公共性/不推荐性,而且我宁愿将任务委托给 .设置动画 .

    这是我的回归函数。

    jQuery.fn.contract_to_original_size = function() {
      var args = Array.prototype.slice.call(arguments);
    
      var callback_with_width_reset = function(){
        callback();
        $(this).width('auto');
      }
    
      args.unshift({ width: $(this).data('original_width') });
    
      if($(this).data('original_width')) {
        $.fn.animate.apply($(this), args );
      } else {
        $(this).width('auto');
      }
    }
    

    我把我所期望的行为表现得很清楚 var callback_with_width_reset ... 论据 args .

    2 回复  |  直到 14 年前
        1
  •  1
  •   gnarf    14 年前

    • 如果你打电话 expand_to_parent_container 同时在多个对象上,继续取消移动 {width: ...} 对象到 args 永远不要让他们后退。
    • contract_to_original_size 不使用 this.each() 也不是 return this ,它将遇到与反复取消移动宽度对象相同的问题。
    • 您可以确保您的代码只设置 original-width 如果尚未设置,请在此处停止一个问题(在扩展时启动扩展/任何不会弄乱它的东西!)
    • 你可以用 $.map() 在你的参数数组中检测和替换回调函数非常容易,如果你仍然觉得需要的话。

    下面是稍作调整的代码:

    jQuery.fn.expand_to_parent_container = function() {
      // instead of Array.prototype, we can grab slice from an empty array []
      var args = [].slice.call(arguments);
    
      return this.each(function(){
        var parent = $(this).parent();
        parent.inner_width = parent.innerWidth();
    
        var inner_outer_differential = $(this).outerWidth(true) - $(this).width();
        // store original width for reversion later
        if (!$(this).data('original_width'))
        {
          $(this).data('original_width', $(this).width());      
        }
    
        args.unshift({ width: parent.inner_width - inner_outer_differential });
        $.fn.animate.apply($(this), args );
        args.shift(); // push the width object back off in case we have multiples
      });
    }
    
    jQuery.fn.contract_to_original_size = function() {
      var args = Array.prototype.slice.call(arguments);
      var callback;
    
      var callback_with_width_reset = function(){
        if (callback) callback.apply(this,arguments);
        // do something else like:
        // $(this).width('auto');
        // you may want to $(this).data('original-width', null); here as well?
      }
    
      args = $.map(args, function(param) {
        // if the parameter is a function, replace it with our callback
        if ($.isFunction(param)) {
          // and save the original callback to be called.
          callback = param;
          return callback_with_width_reset;
        }
        // don't change the other params
        return param;
      });
    
      // we didn't find a callback already in the arguments
      if (!callback) { 
        args.push(callback_with_width_reset);
      }
    
    
      return this.each(function() {
        // rather than shift() the new value off after each loop
        // this is another technique you could use:
    
        // create another copy so we can mess with it and keep our template
        var localArgs = [].slice.call(args); 
        // also - storing $(this) is going to save a few function calls here:
        var $this = $(this);
    
        if($this.data('original_width')) {
          localArgs.unshift({ width: $this.data('original_width') });
          $.fn.animate.apply($this, localArgs );
        } else {
          $this.width('auto');
        }    
      });
    }
    

    Check it out in action on jsFiddle

        2
  •  0
  •   Steven    14 年前

    我目前的解决办法是,除非有更好的办法出现,否则我想我会采取以下办法:

    var arguments_length = arguments.length;
    for(var i = 0; i < arguments_length; i++) {
      if(typeof arguments[i] == 'function') {
        var temp = arguments[i];
        arguments[i] = function(){
          temp();
          $(this).width('auto');
        }
      }
    }
    

    在一个相关的 嗯,那一刻 Array.prototype.slice.call(arguments); 似乎没有预期的效果。最初,不是遍历 arguments ,我将原型调用设置为 args 然后通过 for(arg in args) . 但有很多意想不到的行为。我想,暂时不要这样。

    感觉 错了。

    1. 我的重置 arguments[i] 在很大程度上依赖于不带参数的函数。幸运的是,中的回调函数 .animate