我一直在努力学习如何构建jQuery插件,所以我仍然是新手。由于这是我的第一个插件,我决定尝试一个简单的可折叠面板/盒子(你只能阅读这么多,对吧?)。当click事件触发时,我无法访问对Javascript类对象的引用。我知道事件内部是指触发事件的元素。我也知道我可以在事件发生前做_self = this;
之类的事情,但这只会缓存集合中的最后一个对象。有没有人对如何保持对类对象的引用有任何建议?
谢谢!
这是我的代码。
HTML代码
<div class="mypanel" title="Panel 1">Testing panel 1</div>
<div class="mypanel" title="Panel 2">Testing panel 2</div>
$('.mypanel').collapsiblePanel();
插件代码
var contentVisible = 'showContent', contentNotVisible = 'hideContent';
;(function($) {
var pluginName = 'collapsibleBox';
function Plugin(element, options) {
this.ele = element;
this.$ele = $(element);
var _self = this;
this.options = $.extend({}, $.fn[pluginName].defaults, options);
this.init();
/* Expose methods of Plugin we wish to be public.
* This gets stored when the plugin is created
*/
return {
option: this.option,
destroy: this.destroy
/* Other public methods here */
}
}
$.fn[pluginName] = function(options) {
/* If the first parameter is a string, treat this as a call to a public method. */
if(typeof arguments[0] === 'string') {
var methodName = arguments[0];
var args = Array.prototype.slice.call(arguments, 1);
var returnVal;
this.each(function() {
/* Check that the element has a plugin instance, and that
* the requrested public method exists.
*/
if($.data(this, 'plugin_' + pluginName) && typeof $.data(this, 'plugin_' + pluginName)[methodName] === 'function') {
/* Call the method of the Plugin instance, and Pass it the supplied arguments */
returnVal = $.data(this, 'plugin_' + pluginName)[methodName].appy(this, args);
}
else {
$.error('Method ' + methodName + ' does not exist on jQuery.' + pluginName);
}
});
if(returnVal !== undefined) {
/* If the method returned something, return it */
return returnVal;
}
else {
/* Otherwise, returning 'this' preserves chainability */
return this;
}
}
/* If the first parameter is an object (options), or was omitted,
* instantiate a new instance of the plugin
*/
else if(typeof options === 'object' || !options) {
return this.each(function() {
/* Only allow the plugin to be instantiated once */
if(!$.data(this, 'plugin_' + pluginName)) {
/* Pass options to Plugin constructor, and store Plugin
* instance in the element's jQuery data object
*/
$.data(this, 'plugin_' + pluginName, new Plugin(this, options));
}
});
}
};
$.fn[pluginName].defaults = {
onInit: function() {},
onDestroy: function() {}
};
Plugin.prototype = {
init: function() {
this.createContentArea();
this.createTitleBar();
this.hook('onInit');
},
createContentArea: function() {
/* ... */
},
createTitleBar: function() {
/* ... */
this.$title.click(function() {
if(this.$ele.data('state') == contentVisible) { // The problem is here
this.collapse();
}
else {
this.expand();
}
});
},
expand: function() {
this.$content.slideDown();
this.$ele.data('state', contentVisible);
},
collapse: function() {
console.log(this);
this.$content.slideUp();
this.$ele.data('state', contentNotVisible);
},
/* Use this function to get/set variables */
option: function (key, val) {
if(val) {
this.options[key] = val;
}
else {
return this.options[key];
}
},
destroy: function () {
/* ... */
},
hook: function (hookName) {
if(this.options[hookName] !== undefined) {
this.options[hookName].call(this.ele);
}
}
};
})(jQuery);
答案 0 :(得分:0)
我设法使用.data()
方法和.call()
方法的组合来解决此问题,以确保函数调用的上下文始终是父元素。我设法使用我拥有的模式以及使用jQuery插件创作教程建议的模式来使用它。不管这是否是正确的做法,我不知道。
var methods = {
init: function(options) {
var $this = $(this), data = {};
/* Set a local copy of the options */
data.options = $.extend({}, defaults, options);
/* Create the content area */
data.$content = createContentArea(this);
/* Create the title bar */
data.$title = createTitleBar(this, data.options.header, data.options.title);
/* Show/Hide the content based on the default state passed in */
if(data.options.defaultState == contentVisible) {
data.$content.show();
data.state = contentVisible;
}
else {
data.$content.hide();
data.state = contentNotVisible;
}
/* Add the title click event */
data.$title.click(function() {
methods.toggle.call($(this).parent());
});
/* Add the public methods */
data.methods = {
toggle: methods.toggle,
expand: methods.expand,
collapse: methods.collapse
};
return data;
},
toggle: function() {
var $this = $(this), data = $this.data('plugin_' + pluginName);
if(data.state == contentVisible) {
methods.collapse.call(this);
}
else if(data.state == contentNotVisible) {
methods.expand.call(this);
}
},
expand: function() {
var $this = $(this), data = $this.data('plugin_' + pluginName);
data.$content.slideDown();
data.state = contentVisible;
$this.data('plugin_' + pluginName, data);
},
collapse: function() {
var $this = $(this), data = $this.data('plugin_' + pluginName);
data.$content.slideUp();
data.state = contentNotVisible;
$this.data('plugin_' + pluginName, data);
}
};