Jquery 创建插件 - 如何在动画回调方法中获取对我的对象的 $(this) 引用?
Posted
技术标签:
【中文标题】Jquery 创建插件 - 如何在动画回调方法中获取对我的对象的 $(this) 引用?【英文标题】:Jquery create plugin - how get $(this) reference to my object in animation callback method? 【发布时间】:2012-06-20 23:06:17 【问题描述】:我有以下问题: 我正在创建一个简单的插件 jquery carousel,用于为框中的图像设置动画。 但是我遇到了以下问题,使用OO构建插件,我使用this引用我的对象。
但是其中一个函数使用了 jquery 的 animate 方法。 我想以递归的方式做到这一点。因为动画是一个常数。 但是在回调函数jquery animate中,this指的是对象动画,而不是我在插件本身执行时创建的对象。 如何在动画中调用函数回调对象? 我尝试解决在动画行代码之前直接调用函数 run(),但出现错误:Uncaught RangeError: Maximum call stack size exceeded
如果我将运行函数放在动画回调中,我得到了其他错误:
this.wraper.animate(
top : '-='+image_height,
this.config.speed,
this.run()
)
或
this.wraper.animate(
top : '-='+image_height,
this.config.speed,
function()
this.run();
)
因为 this 是对 this.wraper 对象的引用,而不是对函数对象的引用 似乎有点难以解释。
代码如下:
(function($)
carouselClass = function (el, opts)
this.id = $(el).attr("id");
this.i = 0;
this.config = opts;
this.wraper;
this.count = 0;
this.flag = true;
this.init = function()
// variables
var img = $("#"+this.id).find("img");
this.count = img.length;
//adiciona css necessário a div wrapper
$("#"+this.id).css("position","relative");
$("#"+this.id).css("overflow","hidden");
$("#"+this.id).append("<div></div>");
this.wraper = $("#"+this.id).find("div");
//definições css da div wrapper
this.wraper.css("position","absolute");
this.wraper.css("right","0px");
var direction = this.config.direction;
var container = this.wraper;
//adiciona as imagens ao novo container
img.each(function()
if(direction == "left" || direction == "right")
$(this).css("float", direction)
$(this).css("display", "block");
container.append($(this));
);
//seta a largura e altura do wraper conforme a direção
if(direction == "left" || direction == "right")
this.wraper.width((img.width()*this.count));
this.wraper.height(img.height());
else
this.wraper.height((img.height()*this.count));
this.wraper.width(img.width());
this.run();
this.run = function()
if(this.config.direction == "top")
height = this.wraper.height();
image_height = height/this.count;
for(j = 0; j < (this.count-1); j++)
this.wraper.animate(
top : '-='+image_height,
this.config.speed
)
this.wraper.animate(
top:'0px',
this.config.speed
);
//my problem is this call to function recursive
this.run();
if(this.config.direction == "bottom")
height = this.wraper.height();
image_height = height/this.count;
for(j = 0; j < (this.count-1); j++)
this.wraper.animate(
bottom : '-='+image_height,
this.config.speed
)
this.wraper.animate(
bottom:'0px',
this.config.speed
);
//my problem is this call to function recursive
this.run();
if(this.config.direction == "left")
width = this.wraper.width();
image_width = width/this.count;
for(j = 0; j < (this.count-1); j++)
this.wraper.animate(
left : '-='+image_width,
this.config.speed
)
this.wraper.animate(
left:'0px',
this.config.speed
);
//my problem is this call to function recursive
this.run();
if(this.config.direction == "right")
width = this.wraper.width();
image_width = width/this.count;
for(j = 0; j < (this.count-1); j++)
this.wraper.animate(
right : '-='+image_width,
this.config.speed
)
this.wraper.animate(
right:'0px',
this.config.speed
);
//my problem is this call to function recursive
this.run();
;
$.fn.carousel = function(options)
var opts = $.extend(, $.fn.carousel.defaults, options);
return this.each(function ()
var instance = new carouselClass($(this), opts);
/**********Start the carousel ***********/
instance.init();
);
$.fn.carousel.defaults =
'direction': "left",
'speed': 3000
;
)(jQuery);
如果我以这种方式调用,插件工作,但只有我设置为 i var 的次数,我希望轮播不断变化:
this.prepare = function()
this.i++;
if(this.i < 3)
this.run();
this.run = function()
if(this.config.direction == "top")
height = this.wraper.height();
image_height = height/this.count;
for(j = 0; j < (this.count-1); j++)
this.wraper.animate(
top : '-='+image_height,
this.config.speed
)
this.wraper.animate(
top:'0px',
this.config.speed
);
this.prepare();
【问题讨论】:
【参考方案1】:this.setAnimation=function(state)
var obj=this;
if(state)obj.animationID=setInterval(function()
obj.run();
,obj.config.speed);
else
clearInterval(obj.animationID);
;
你在寻找这样的东西吗?
setAnimation(true)//start Animation
【讨论】:
【参考方案2】:尝试使用$.proxy()
this.wraper.animate(
top : '-='+image_height,
this.config.speed,
$.proxy(function()
this.run();
, this)
)
【讨论】:
【参考方案3】:一般来说,在 jQuery 插件中,使用“this”会让人感到困惑。原因正是您所指出的 - “this”完全依赖于上下文,并且因为 jQuery 通常依赖于链接 - 关键字的值经常变化。
我的建议是——而不是使用“this”——利用闭包的力量。一个例子:
// Instead of...
carouselClass = function (el, opts)
this.id = $(el).attr("id");
this.i = 0;
this.config = opts;
this.wraper;
this.count = 0;
this.flag = true;
this.init = function()
;
// Try...
var Carousel = function (el, options)
var $el = (el instanceOf jQuery) ? el : $(el);
var defaults =
id: $(el).attr('id'),
currentIndex: 0,
count: 0,
flag: true,
config:
// Defaults go here.
;
var settings = $.extend(true, , defaults, options);
var fx =
init: function (newOptions)
settings = $.extend(true, , defaults, settings, newOptions);
// Now you can do other init stuff based on settings.Option,
// rather than caring what "this" is equal to.
,
run: function ()
// Note that you can use settings.Option here, too - and again,
// you don't care what "this" is, because settings is within
// an outer closure.
,
prepare: function ()
// Do your prepare stuff here.
;
;
使用这种意识形态 - 你的功能可能会变成这样:
run = function()
if (settings.config.direction == "top")
var height = settings.wrapper.height();
var image_height = height / settings.count;
for(j = 0; j < (settings.count - 1); j++)
settings.wrapper.animate(
top: '-=' + image_height ,
settings.config.speed
)
settings.wrapper.animate( top: '0px' , settings.config.speed);
fx.prepare();
我还应该注意 - 此代码不打算用作直接的、有效的替代您的代码 - 只是一个示例,说明如何通过构造代码以利用闭包来避免“这个”问题,以及基于闭包的设置机制。
【讨论】:
感谢您的出色解释。但是我现在需要的任务很简单,我使用第三个答案并且它有效,未来将改进插件以用于其他项目,这个使用你的技巧和clousure以上是关于Jquery 创建插件 - 如何在动画回调方法中获取对我的对象的 $(this) 引用?的主要内容,如果未能解决你的问题,请参考以下文章