Last night, I was trying to help Glen Lipka write a jQuery plugin. I love love love jQuery, but I have never written a jQuery plugin, so at first, I was very confused as to what was going on. After a while, I started to get my bearings, figuring out what THIS pointed to, and what I had access to, and all that jazz. Still, I am not sure that I am on the right path, so I thought I would take some time this morning to write my very first jQuery plugin (to completion) and post it up so that people can basically pick it apart and tell me how much I suck so that I can get better at doing this :) I am used to being in objects in Javascript, but never really at this level of complexity.
My first jQuery plugin is called Scared. It takes all elements defined by your jQuery selector and makes them scared to be touched. To do this, I am binding the mouse over and mouse move events in such a way that when you try to click on the elements or move over them, they freak out and move away. Now, I am not sure how this interacts with different styles of positioning and all that, but for this demo, I am just going to keep it simple.
See the jQuery Scared Plugin Demo Here
Here is the HTML for the page:
Launch code in new window » Download code as text file »
As you can see, the power of jQuery comes from its insanely simple syntax. To initialize the document and apply the Scared plugin to the elements, all I have to do is run this:
Launch code in new window » Download code as text file »
This finds all input elements that are of type Button and then applies the Scared plugin behavior. jQuery is so freakin' cool.
Now, on to the complicated stuff - the actually jQuery plugin:
Launch code in new window » Download code as text file »
The jQuery plugin works by binding the onmouseover and onmousemove events to event handlers defined within the Scared function. Once the event handler fire, they pick a random direction and random distance and move the target node in such a way that it travels away from the cursor. Now, here's where I get a bit fuzzy - are these handlers now part of the jQuery object instance (which is what it seems like to me)? I am used to having objects with prototypes and shared functions, but something about this just confuses me at a core level. I feel like I am very close to getting it, I just need to bridge a small gap.
So that's my first jQuery plugin, any and all feedback is appreciated. I would love to really wrap my head around this process and be able to make some cool plugins.
Download Code Snippet ZIP File
Comments (6) | Post Comment | Ask Ben | Permalink | Other Searches | Print Page
Ben, I think you can simplify a few little things.
Instead of using two statements, you can just use (except you did that for readability):
return this.each(...);
(You could even use chaining in here, like return this.css(...).each() )
More important: I think it is not necessary and even potentially dangerous to attach the OnMouseOver function to the jQuery object.
You can just use the power of closures. Say you define the function like:
var OnMouseOver = function( jNode ){ ... }
you can later on bind it like:
jNode.mouseover(function(){
OnMouseOver( jNode );
});
This also saves you from the need to define the "scared" variable.
Potentially dangerous, because you may find yourself overwriting an internal jQuery function on that specific object, which would give you a really hard time of debugging.
Apart from that, my first plugin wasn't looking that good :-)
Happy coding, Klaus
Posted by Klaus Hartl on Jul 3, 2007 at 3:41 PM
@Klaus,
Thank you so much for the feedback. I really like the idea of storing the event handlers as VAR'd variables (var OnMouseOver = ...). I totally didn't want to store anything in the THIS scope, so that would take care of the problem quite nicely. Sometimes I get so involved in the details, the little solutions like that don't occur to me.
Also, I didn't realize that you could just return the result of Each(). However, like you say, I do opt for a little more readability.
And, as far as the "scared" variable, this shouldn't be a problem because, like the event handlers you were suggesting, it is VAR'd to the function, not to the jQuery object itself (right??).
Anyway, this is really helpful. Thanks a lot.
Posted by Ben Nadel on Jul 3, 2007 at 5:01 PM
Sure, the scared variable isn't much of a problem, it is just obsolete, if you bind the handlers like I proposed. The only reason I see you created it, is because you needed something other then "this" to refer to, which is not required any longer.
You can do return this.each(), because this.each() also returns the this, it is the same chaining principle as in $('div').show().each(...) just from a different perspective (from the inside) so to say maybe.
Posted by Klaus Hartl on Jul 3, 2007 at 5:36 PM
Good point. Sweet!
Posted by Ben Nadel on Jul 3, 2007 at 5:39 PM
Nice :)
Just a short note, nothing special, instead of $( "input[@type='button']" ) you can use the shorter and faster selector $("input:button") as described here:
http://docs.jquery.com/Selectors#Form_Selectors
Quote: "Using :radio is mostly the same as [@type=radio], but should be slightly faster. Good to know when working with large forms."
regards
thomas
Posted by Thomas on Aug 29, 2007 at 8:53 AM
@Thomas,
Awesome tip! Still learning all this jQuery stuff. Gotta learn more about these selectors.
Posted by Ben Nadel on Aug 29, 2007 at 8:55 AM