2011-10-10 126 views
1

我開發了一個jQuery插件,它可以執行顯示和隱藏兩個連續動畫的內容。我對使用單個元素時插件的行爲感到滿意,但是當頁面上有兩個元素在插件調用中使用相同的類名時,我會返回四個回調函數。看起來這個插件並不完全正確,我希望有任何提示或幫助可以讓我更接近完成這個插件。jQuery插件 - 返回的回調太多

我熱衷於提高我的代碼質量,也會很感激任何一般的反饋。

插件的工作示例可以在這裏找到:http://jsfiddle.net/nijk/sVu7h/

插件代碼如下:

(function($){ 
$.fn.showHide = function(method, duration, options, callback){ 
    //console.log(method, duration, options, callback); 
    var animating = false; 
    var defaults = { 
     $elem: this, 
     easing: "swing" 
    } 
    var _sh = this; 
    var init = function(){ 
      _sh.method = method; 
      if("show" !== _sh.method && "hide" !== _sh.method){ 
       _sh.method = "show"; 
      } 
      if(duration < 0 || (typeof(duration) == "string" && ("slow" !== duration && "normal" !== duration && "fast" !== duration))){ 
       duration = "normal"; 
      } 
      console.log(duration, typeof(duration)); 
      if(typeof(options) == "function"){ 
       callback = options; 
       options = {}; 
      } 
      _sh.config = $.extend({}, defaults, options); 
     if(!animating){ 
      //return _sh.each(function(index){ 
       //console.log("found element number: " + (index + 1)); 
       eval(_sh.method)();    
      //}); 
     } 
    } 
    var show = function(){ 
     animating = true; 
     _sh.config.$elem.wrap('<div class="show-hide"/>').parent().hide(); 
     _sh.config.$elem.css({"opacity":0, "display":"block"}); 
     console.log("element height:", _sh.config.$elem.parent().outerHeight()); 
     _sh.config.$elem.parent().slideDown(duration, _sh.config.easing, function(){ 
      _sh.config.$elem.animate({"opacity": 1}, duration, _sh.config.easing, function(){ 
        console.log("show final cleanup called"); 
        _sh.config.$elem.addClass("visible").unwrap(); 
        $.isFunction(callback) && callback(); 
        animating = false; 
      }); 
     }); 
    }; 
    var hide = function(){ 
     animating = true; 
     _sh.config.$elem.wrap('<div class="show-hide"/>'); 
     _sh.config.$elem.animate({"opacity":0}, duration, _sh.config.easing, function(){ 
      _sh.config.$elem.slideUp(duration, _sh.config.easing, function(){ 
       console.log("hide final cleanup called"); 
       _sh.config.$elem.removeClass("visible").hide().unwrap(); 
       $.isFunction(callback) && callback(); 
       animating = false; 
      }); 
     }); 
    } 
    init(); 
    return this; 
} 
})(jQuery); 

@ david.mchonechase:非常感謝你的解釋和代碼示例。

我已經對回調做了一些修改,以便返回'this'的正確上下文。任何改善代碼的建議將不勝感激。

工作代碼在這裏更新:http://jsfiddle.net/nijk/sVu7h/和如下:

(function($){ 
    $.fn.showHide = function(method, duration, options, callback){ 
    var animating = false; 
    var defaults = { easing: "swing" }; 
    var _sh = this; 
    _sh.method = show; 

    if("hide" === method){ 
     _sh.method = hide; 
    } 
    if(duration < 0 || (typeof(duration) == "string" && ("slow" !== duration && "normal" !== duration && "fast" !== duration))){ 
     duration = "normal"; 
    } 
    if(typeof(options) == "function"){ 
     callback = options; 
     options = {}; 
    } 
    _sh.config = $.extend({}, defaults, options); 

    function show(elem){ 
     animating = true; 
     elem.wrap('<div class="show-hide"/>').parent().hide(); 
     elem.css({"opacity":0, "display":"block"}); 
     elem.parent().slideDown(duration, _sh.config.easing, function(){ 
      elem.animate({"opacity": 1}, duration, _sh.config.easing, function(){ 
        elem.addClass("visible").unwrap(); 
        $.isFunction(callback) && callback.call(this); 
        animating = false; 
      }); 
     }); 
    }; 
    function hide(elem){ 
     animating = true; 
     elem.wrap('<div class="show-hide"/>'); 
     elem.animate({"opacity":0}, duration, _sh.config.easing, function(){ 
      elem.slideUp(duration, _sh.config.easing, function(){ 
       elem.removeClass("visible").hide().unwrap(); 
        $.isFunction(callback) && callback.call(this); 
        animating = false; 
      }); 
     }); 
    }; 

    if(!animating){ 
     // loop through each element returned by jQuery selector 
     return this.each(function(){ 
      _sh.method($(this)); 
     }); 
    } 
    } 
})(jQuery); 

回答

2

的問題是全局變量和父()調用的混合物。 _sh。$ elem變量包含兩個元素(每個jQuery選擇器結果一個)。 show函數中的_sh.config。$ elem.parent()。slideDown調用被調用兩次。一旦完成,它就會爲每個「showMe」元素運行_sh.config。$ elem.animate一次。所以,parent()。slideDown被調用兩次,然後調用_sh.config。$ elem.animate兩次。

我通常會嘗試避免jQuery插件中的全局變量用於顯示和隱藏等功能,但關鍵部分是元素。 (該動畫全局變量是有道理的,雖然)。

我覺得像這樣的工作:

(function($){ 
    $.fn.showHide = function(method, duration, options, callback){ 
     //console.log(method, duration, options, callback); 
     var animating = false; 
     var defaults = { 
      //$elem: this, 
      easing: "swing" 
     } 
     var _sh = this; 
     var init = function(){ 
      var methodFn = show; // reference actual function instead of string, since eval is evil (usually) 
      if("hide" === method){ 
       methodFn = hide; 
      } 
      if(duration < 0 || (typeof(duration) == "string" && ("slow" !== duration && "normal" !== duration && "fast" !== duration))){ 
       duration = "normal"; 
      } 
      console.log(duration, typeof(duration)); 
      if(typeof(options) == "function"){ 
       callback = options; 
       options = {}; 
      } 
      _sh.config = $.extend({}, defaults, options); 
      if(!animating){ 
       // loop through each element returned by jQuery selector 
       _sh.each(function(){ 
        methodFn($(this)); // pass the single element to the show or hide functions 
       }); 
      } 
     } 
     var show = function(elem){ 
      animating = true; 
      elem.wrap('<div class="show-hide"/>').parent().hide(); 
      elem.css({"opacity":0, "display":"block"}); 
      console.log("element height:", elem.parent().outerHeight()); 
      elem.parent().slideDown(duration, _sh.config.easing, function(){ 
       elem.animate({"opacity": 1}, duration, _sh.config.easing, function(){ 
         console.log("show final cleanup called"); 
         elem.addClass("visible").unwrap(); 
         $.isFunction(callback) && callback(); 
         animating = false; 
       }); 
      }); 
     }; 
     var hide = function(elem){ 
      animating = true; 
      elem.wrap('<div class="show-hide"/>'); 
      elem.animate({"opacity":0}, duration, _sh.config.easing, function(){ 
       elem.slideUp(duration, _sh.config.easing, function(){ 
        console.log("hide final cleanup called"); 
        elem.removeClass("visible").hide().unwrap(); 
        $.isFunction(callback) && callback(); 
        animating = false; 
       }); 
      }); 
     } 

     init(); 
     return this; 
    } 
})(jQuery);