#javascript #jquery #plugins
#javascript #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 amp;amp; "hide" !== _sh.method){
_sh.method = "show";
}
if( duration < 0 || (typeof(duration) == "string" amp;amp; ("slow" !== duration amp;amp; "normal" !== duration amp;amp; "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) amp;amp; 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) amp;amp; callback();
animating = false;
});
});
}
init();
return this;
}
})(jQuery);
@david.mchonechase: Большое вам спасибо за ваше объяснение и пример кода.
Я внес некоторые изменения в обратные вызовы, чтобы возвращался правильный контекст для «этого». Любые предложения по улучшению кода будут с благодарностью приняты.
Рабочий код обновлен здесь: 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" amp;amp; ("slow" !== duration amp;amp; "normal" !== duration amp;amp; "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) amp;amp; 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) amp;amp; callback.call(this);
animating = false;
});
});
};
if(!animating){
// loop through each element returned by jQuery selector
return this.each(function(){
_sh.method($(this));
});
}
}
})(jQuery);
Ответ №1:
Проблема заключается в смешении глобальных переменных и вызова parent() . Переменная _sh.$elem содержит два элемента (по одному на результат выбора jQuery). Вызов _sh.config.$elem.parent().slideDown в функции show вызывается дважды. После завершения он запускает _sh.config.$elem.animate один раз для каждого элемента «ShowMe». Итак, 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" amp;amp; ("slow" !== duration amp;amp; "normal" !== duration amp;amp; "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) amp;amp; 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) amp;amp; callback();
animating = false;
});
});
}
init();
return this;
}
})(jQuery);