A Convenient Way to Write a jQuery Plugin(redirected from blargh/2014/1/a-convenient-way-to-write-a-jquery-plugin)
This article was originally published in my blog (affectionately referred to as blargh) on . The original blog no longer exists as I've migrated everything to this wiki.
The original URL of this post was at https://tmont.com/blargh/2014/1/a-convenient-way-to-write-a-jquery-plugin. Hopefully that link redirects back to this page.
I've written quite a few jQuery plugins in my day. The early ones were horrible
mishmashes of spaghetti code interlaced with $.fn
. Back then I
didn't even know $.fn
was supposed to be. I thought fn
was just some magic string that did something magical, and then you suddenly
had written a jQuery plugin!
Since then, for decently sophisticated plugins (i.e. ones that create state)
I've started constructing them in a more consistent manner. More specifically,
I totally ripped off the format that the Bootstrap
authors used for their plugins, like $('selector').button('reset')
.
I had to hack the button plugin because for some reason it put every action
in the event loop with setTimeout
and I couldn't rely on things
occurring in the proper order. As I was cursing the authors out for doing something
so annoying, I was simultaneously praising them for writing their plugins in a way
that was consistent and easy to work with. Even if they don't use semicolons.
The heathen bastards.
Before I get to the actual format, I want to emphasize that for simple plugins, doing things like this is fine (and probably preferable):
$.fn.redOrBlueLol = function() {
return this.each(function() {
var $this = $(this);
$this.css('color', $this.css('color') === 'red' ? 'blue' : 'red');
});
};
If all you're doing is some minor DOM manipulation, then you don't really need to worry about writing your plugin in some consistent format.
The Format
First, you have your stateful object and its prototype:
var ns = 'my-plugin';
function MyStatefulObject($element, options) {
this.$element = $element;
this.doStuff = !!options.doStuff;
}
MyStatefulObject.prototype = {
helloWorld: function(name) {
name = name || 'world';
this.$element.text('Hello ' + name + '!');
},
destroy: function() {
// stuff to tear down all the mess you've made
this.$element.off('.' + ns);
}
};
Then the actual definition of the plugin:
$.fn.myPlugin = function(options) {
options = options || {};
return this.each(function() {
var $element = $(this),
thing = $element.data(ns),
method = typeof(options) === 'string' ? options : '';
if (!thing) {
var realOptions = !options || typeof(options) !== 'object' ? {} : options;
$element.data(ns, (thing = new MyStatefulObject($element, realOptions));
}
if (typeof(thing[method]) === 'function') {
thing[method].apply(thing, [].slice.call(arguments, 1));
}
});
};
And that's it. Now you can use your plugin as such:
$('selector').myPlugin('helloWorld');
$('.billy').myPlugin('helloWorld', 'Billy');
$('selector, .billy').myPlugin('destroy');
You can see an example of this in action in an audio player plugin I've been working lately: jquery.rach3.js
And that's it. Nothing very complicated or magical about it. Just convenient.