Javascript jquery插件控制器相互覆盖

Javascript jquery插件控制器相互覆盖,javascript,jquery,inheritance,jquery-plugins,scope,Javascript,Jquery,Inheritance,Jquery Plugins,Scope,我正在使用两个jquery插件——一个用于选项卡,另一个用于缩略图库——来创建选项卡库。在我尝试引入一个简单的mvc模式之前,一切都进展顺利。现在,不知何故,第二个插件初始化后的控制器会覆盖第一个插件-当第一个插件尝试使用第二个插件的控制器时,会导致很多“new_view.tab未定义” 以下是选项卡的代码 ( function( $ ) { // private vars var settings; var Model = ( function( ) { var pub = { }

我正在使用两个jquery插件——一个用于选项卡,另一个用于缩略图库——来创建选项卡库。在我尝试引入一个简单的mvc模式之前,一切都进展顺利。现在,不知何故,第二个插件初始化后的控制器会覆盖第一个插件-当第一个插件尝试使用第二个插件的控制器时,会导致很多“new_view.tab未定义”

以下是选项卡的代码

( function( $ ) {

// private vars
var settings;

var Model = ( function( ) {
    var pub = { };
        current_view = null;

    pub.get_current = function( ) {
        if( current_view ) {
            return current_view;
        } else {
            return false;
        }
    }
    pub.set_current = function( new_view ) {
        if( current_view ) console.log( 'current view is ' + current_view.number );
        current_view = new_view;
        if( current_view ) console.log( 'current view is now ' +current_view.number );
    }
    return pub;
})( );

var Controller = ( function( Model ) {
    var pub = { };
        model = Model;

    pub.update = function( new_view ) {
        console.log( 'tab controller update' );

        settings.update( model.get_current_view, new_view, function( callback ) {
            if( model.get_current( ) ) {
                model.get_current( ).tab.removeClass( settings.active_class );
            }
            model.set_current( new_view );
            new_view.tab.addClass( settings.active_class );
        });
    }
    pub.close = function( new_view ) {
        settings.close_callback(  );
        pub.model.set_current( null );
    }
    console.log( 'in tabs controller');
    console.log( pub );
    return pub;
})( Model );

console.log( 'in tabs')
console.log( Controller );

var View = ( function( Controller ) {
    var pub = { };
        controller = Controller;

    pub.update = function( new_view ) {
        controller.update( new_view );
    }

    pub.close = function( new_view ) {
        controller.update( new_view );
    }

    return pub;
})( Controller );

/* private closures */
function Tab( tab, tab_content, close, number ) {
    this.tab = tab;
    this.tab_content = tab_content;
    this.close = close;
    this.number = number;
    var Tab = this;

    // listeners
    tab.bind( 'click.tab', function( evnt ) {
        console.log( 'tab' + number + ' clicked' );
        evnt.preventDefault( );
        if( Tab.tab.hasClass( settings.active_class ) ) return;
        Tab.update( Tab );
    });

    close.bind( 'click.close', function( evnt ) {
        console.log( 'tab' + number + ' close clicked' );
        evnt.preventDefault( );
        Tab.close( Tab );
    });
}
Tab.prototype = View;

//public methods
var methods = {
    init : function( options ) {

        //defaults
        var defaults = {
            'tab_class': 'tab',
            'content_class' : 'content',
            'close_class': 'close',
            'active_class': 'active',
            'animate_open': function( arg ) {
                $( arg ).show( );
            },
            'animate_close': function( arg ) {
                $( arg ).hide( );
            },
            'tab_click_callback': function( ) { },
            'close_callback': function( ){ }
        };

        return this.each( function( ) {
            //update defaults with user options
            if( options ) {
                settings = $.extend( true, { }, defaults, options );
            } else {
                settings = defaults;
            }

            var container = $( this );
            var tabs = $( '.' + settings.tab_class, container ).children( );
            var content = $( '.' + settings.content_class, container );
            var close = $( '.' + settings.close_class, container );
            var len = tabs.length;
            var i = 0;
            tabs.each( function( index ) {
                var current_tab = $( this );
                new Tab( current_tab, $( content[ index ] ), $( close[ index ] ), index + 1 );
            });
        });//end return
    },//end init
    destroy: function( ) {
        return this.each( function( ) {
            methods = null;
        });
    }
};//end methods

//add function to jquery
$.fn.id_tabs = function( method ) {
    if ( methods[method] ) {
        return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
        return methods.init.apply( this, arguments );
    } else {
        $.error( 'Method ' +  method + ' does not exist on jQuery.id_tabs' );
    }    
};

})(jQuery);
画廊呢

(function($) {

var settings;

/* private */   
var Model = ( function( ) {
    var pub = { };
        current_view = null;

    pub.get_current = function( ) {
        if( current_view ) {
            return current_view;
        } else {
            return false;
        }
    }
    pub.set_current = function( new_view ) {
        if( current_view ) console.log( 'current view is ' + current_view.number );
        current_view = new_view;
        if( current_view ) console.log( 'current view is now ' +current_view.number );
    }
    return pub;
})( );

var Controller = ( function( Model ) {
    var pub = { };
        model = Model;

    pub.update = function( view ) {
        console.log( 'gallery controller update' );
        settings.update( model.current_view, view );
        if( model.get_current( ) ) {
            model.get_current( ).thumb.removeClass( settings.active_class );
        }
        model.set_current( view );
        view.thumb.addClass( settings.active_class );
    }
    console.log( 'in gallery controller');
    console.log( pub );
    return pub;
})( Model );

console.log( 'in gallery');
console.log( Controller );

var View = ( function( Controller ) {
    var pub = { };
        controller = Controller;

    console.log( 'in gallery view' );
    console.log( controller );

    pub.update = function( new_view ) {
        console.log( 'in gallery update');
        console.log( controller );
        controller.update( new_view );
    }
    return pub;
})( Controller );

function Thumb( thumb, pic, number ) {
    this.thumb = thumb;
    this.pic = pic;
    this.number = number;
    var Thumb = this;

    this.hide = function( callback ) {

        console.log( Thumb );
        settings.animate_out( Thumb, function( ) {
            if( callback ) callback( );
        });
    }
    this.show = function( callback ) {
        console.log( Thumb );
        settings.animate_in( Thumb, function( ) { 
            if( callback ) callback( );
        });
    }
    thumb.bind( 'click.thumb', function( evnt ) {
        console.log( 'pic' + number + ' clicked' );
        evnt.preventDefault( );
        if( Thumb.thumb.hasClass( settings.active_class ) ) return;
        Thumb.update( Thumb );
    });
};
Thumb.prototype = View;

/* public */
var methods = {
    init : function( options ) {

        //defaults
        var defaults = {
            'container_id': 'content',
            'active_class' : 'active',
            'movie_class': 'movie',
            'animate_in': function( arg ) {
                $( arg ).fadeIn( );
            },
            'animate_out': function( arg, callback ) {
                $( arg ).fadeOut( );
                callback( );                    
            },
            'update' : function( current, new_view, callback) {
                if( current ) current.pic.fadeOut( );
                new_view.pic.fadeIn( );
                if( callback ) callback( );
            }
        };

        return this.each( function( ) {
            //update defaults with user options
            if( options ) {
                settings = $.extend( true, { }, defaults, options );
            } else {
                settings = defaults;
            }

            var obj = $( this );
            var li = $( 'li', obj );
            var obj_class = obj.attr( 'id' );
            var container = $( '#' + settings.container_id );
            var content = $( '.' + obj_class, container );

            li.each( function( index ) {
                var current_li = $( this );
                var current_content = $( content[ index ] );
                var src = current_li.children( ).children( ).hide( ).attr( 'src');
                var href = current_li.children( ).attr( 'href');
                current_li.css( 'background-image', 'url(' + src + ')' );
                current_content.css( 'background-image', 'url(' + href + ')' );         
                new Thumb( current_li, current_content, index );
            });
        });//end return
    },//end init
    destroy: function( ) {
        return this.each( function( ) {
            methods = null;
        });
    },
    hide_current: function( callback ) {
        console.log( 'hide_current' );
        if( Model.current_view ) {
            settings.animate_out( Model.current_view, function( ) {
                Model.current_view.thumb.removeClass( settings.active_class );
                Model.current_view = null;
                if( callback ) callback( );
            });
        } else {
            callback( );
        }
    }
};//end public methods

//add function to jquery
$.fn.id_gallery = function( method ) {
    if ( methods[method] ) {
        return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
        return methods.init.apply( this, arguments );
    } else {
        $.error( 'Method ' +  method + ' does not exist on jquery.id_gallery' );
    }    
};

})(jQuery);
我假设某个东西正在范围链上爬行,但由于在每个闭包中本地定义了“控制器”,我不明白如何进行

更令人沮丧的是,我启动了一个JSFIDLE并在那里工作,但我一辈子都无法找出它与我的生产代码之间的区别。


请帮助

我不熟悉为jQuery编写插件的这种风格,因此可能我遗漏了一些明显的东西,但我确实看到有一个名为“controller”的全局变量在这两个位置都赋值。这可能就是问题所在吗?

完全是。昨天一整天都在折磨我的人。谢谢。一般来说,我对编写jquery插件和javascript还不熟悉。但是我已经读了很多关于它的书(大部分是博客之类的),所以我把这些第一次尝试的东西拼凑在一起,从我觉得有意义的地方。如果你知道更好的方法,或者如何改进这种风格,我很想听听你的想法。我从来没有专门使用MVC模式编写过jQuery插件,但看起来它可能是一个很好的例子。