jquery 插件控制器互相覆盖
我使用两个 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);
,我假设有些东西正在作用域链上爬行,但是由于“控制器”在每个闭包中本地定义,我不明白如何进行。
更令人沮丧的是,我启动了一个 jsFiddle 并让它在那里工作,但我一生都无法弄清楚它与我的生产代码之间的区别。 http://jsfiddle.net/noTxt/vWsJw/
请帮忙
I'm using two jquery plugins - one for tabs and one for a thumbnail gallery - to create a tabbed gallery. Everything was going smoothly until I tried to introduce a simple mvc pattern. Now, somehow, the controller from whichever plugin is initialized second overrides the first one - leading to a lot of "new_view.tab is undefined" as the first plugin tries to use the second's controller.
Here's the code for tabs
( 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);
and for the gallery
(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);
I assume that something is crawling up the scope chain, but with "Controller" defined locally within each closure, I don't understand how.
Even more frustrating, I started a jsFiddle and got it working there, but cannot for the life of me figure out the difference between that and my production code.
http://jsfiddle.net/noTxt/vWsJw/
please help
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不熟悉这种编写 jQuery 插件的风格,所以也许我遗漏了一些明显的东西,但我确实看到有一个名为“controller”的全局变量在两个地方都分配了。这也许是问题所在?
I'm not familiar with this style of writing plugins for jQuery so perhaps I'm missing something obvious, but I do see that there is a global variable called "controller" that is assigned in both places. Is this perhaps the issue?