0

我有以下问题:我正在创建一个简单的插件 jquery carousel,用于为框中的图像设置动画。但是我遇到了以下问题,使用OO来构建插件,我使用它来引用我的对象。

但是其中一个函数使用了 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.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();             
            }
                 }
4

3 回答 3

0

尝试使用$.proxy()

this.wraper.animate(
                   {top : '-='+image_height},
                        this.config.speed,
                        $.proxy(function(){
                            this.run();
                        }, this)
                   )
于 2012-06-18T22:45:06.870 回答
0
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
于 2012-06-18T22:46:33.837 回答
0

通常,在 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();
    }
}

我还应该注意 - 此代码不打算用作您的直接、有效的替代品 - 只是一个示例,说明如何通过构造代码以利用闭包和基于闭包的优势来避免“这个”问题设置机制。

于 2012-06-18T23:00:59.213 回答