How to make a self contained jQuery plugin that finds the tallest image height?
I have been trying to make this to be a little jQuery plugin that I can reuse in the future without having to write the following into my actions.js file in full.
This works when loaded in the same file where I set the height using my variable tallest
.
var tallest = null;
$('.slideshow img').each(function(index) {
if ($(this).height() >= tallest ) {
tallest = $(this).height();
}
});
$('.slideshow').height(tallest);
This works and will cycle through all the items, then set the value of tallest
to the greatest height found. The following however does not work:
This would be the plugin, loaded from its own file (before the actions.js file that contains the parts using this):
(function($){
$.fn.extend({
tallest: function() {
var tallest = null;
return this.each(function() {
if ($(this).height() >= tallest ) {
tallest = $(this).height();
}
});
}
});
})(jQuery);
Once loaded I am trying to use it as follows:
$('.slideshow img').tallest();
$('.slideshow').height(tallest);
However the above two lines return an error of 'tallest is undefined'. How can I make this work? Any ideas would be appreciated. Thinking about this even more the perfect usage of this would be as follows:
$('.container').heigh开发者_JAVA百科t(tallest('.container item'));
But I wouldn't even know where to begin to get this to work in the manner that you pass the object to be measured into the function by adding it into the brackets of the function name.
Thanks for reading,
Jannis
The reason you're getting 'tallest is undefined' is because tallest
only exists inside the scope in which it is defined and can't be accessed from outside. You need to encapsulate all your logic inside the plugin. Here is how you might do it:
(function($) {
$.fn.tallest = function(itemsSelector) {
return this.each(function() {
var $this = $(this),
$items = $(itemsSelector, this),
tallest = 0;
$items.each(function() {
var $thisItem = $(this);
if ($thisItem.height() > tallest) {
tallest = $thisItem.height();
}
});
$this.height(tallest);
});
};
})(jQuery);
// used like this:
$('.container').tallest('.item');
Edit:
Starting a variable name with a $
is a convention inspired by Hungarian Notation and is used to indicate that the variable contains a jQuery object. It's not required to name your variables this way, but I find it useful.
I also use var $this = $(this);
here to store a jQuery object that wraps the DOM object currently being operated on. The reason for doing this is for performance - every time you need to reference the current object in the loop, you can use $this
and won't be creating an identical new object in memory. In this example the benefit is not very clear because $this
is only used once anyway. This technique is also used inside the inner loop by assigning the current object to $thisItem
. Since this object is referred to twice in the loop, you save an object instantiation.
Try this shorter (and more generalized) version of what you are trying to do:
$.fn.extend({
max: function(prop) {
// create an array of all property values
var props = $.map(this, function(i) { return i[prop]; });
// return the result of Math.max() applied to this array
return Math.max.apply(Math, props);
}
});
Use it like this:
var tallest = $(".slideshow img").max("height");
var widest = $(".slideshow img").max("width");
If you use several JavaScript libraries in parallel you might want to ensure that $
means jQuery
within the plugin. The usual way to do this is to wrap the above in an anonymous function, like this:
(function($) {
$.fn.extend({
// ...
});
)(jQuery);
$.fn.tallest = function(outer, margins) {
var fn = outer ? "height" : "outerHeight";
return Math.max.apply(Math, $.map(this, function(el) {return $(el)[fn](margins);}));
};
精彩评论