Tried to build a simple tooltip plugin in plain javascript.
I digged jquery extend but it s a bit complicated for me.
I tried to make and put bcolor
as default setting in my code and i think i'ts not a good way when we want to put more than 1 defaults.
How can i make default settings in my plugin?
var Tooltip = function(selector, bcolor) { this.targetElement = document.querySelectorAll(selector); this.bcolor = bcolor; if (this.bcolor == null || typeof this.bcolor !== "string") { this.bcolor = "#333"; } if (this.targetElement == null) { console.log("Ooops, error!") } return this; } Tooltip.prototype.tooltip = function() { for (var i = 0; i < this.targetElement.length; i++) { var text = this.targetElement[i].getAttribute("data-tooltip"); this.targetElement[i].style.position = "relative"; var span = document.createElement("span"); this.targetElement[i].appendChild(span); span.style.position = "absolute"; span.style.top = "-25px"; span.style.left = "-20px"; span.style.padding = "4px" span.style.borderRadius = "5px"; span.style.backgroundColor = this.bcolor; span.style.color = "#fff"; span.innerHTML = text; } } var box = new Tooltip(".box", "red"); box.tooltip();
1 Answers
Answers 1
First, let's look at how to easily support multiple options. A common solution to this is to have your constructor take in a "configuration" object instead of just simple string or number arguments. Consider using this form instead:
var Tooltip = function(selector, options) { this.targetElement = document.querySelectorAll(selector); this.options = options; ... }; var box = new Tooltip(".box", { color: "red" });
Notice that instead of passing a single value, we pass in an object that contains that single value. But that object can potentially have many configuration options in it — not just one! For example, you could pass in:
var box = new Tooltip(".box", { backgroundColor: "red", textColor: "white", fontSize: 12, animated: true, animationSpeed: 1000 });
When you need to access any of those options, your code can simply use the reference to the options object: For example, instead of this.bcolor
, you might use this.options.backgroundColor
. Here's your code above, extended with some more options:
Tooltip.prototype.tooltip = function() { for (var i = 0; i < this.targetElement.length; i++) { ... span.style.backgroundColor = this.options.backgroundColor; span.style.color = this.options.textColor; span.style.fontSize = this.options.fontSize + "px"; ... } }
So that's how you'd handle multiple options; but what about default values for each? To do that, you'd want to first define somewhere what the default values look like:
Tooltip.prototype.defaultOptions = { backgroundColor: "#FF9", textColor: "black", fontSize: 12, animated: false, animationSpeed: 1000 };
And then your constructor could spin over the defaultOptions
, using its values to fill in any missing "holes" in the provided options
object:
var Tooltip = function(selector, options) { this.targetElement = document.querySelectorAll(selector); this.options = options; for (var optionName in this.defaultOptions) { if (typeof this.options[optionName] === 'undefined') this.options[optionName] = this.defaultOptions[optionName]; } ... };
A test against a typeof
for the value of undefined
is true only if the value doesn't exist, so this for-loop copies any values from defaultOptions
to options
, as long as they don't already exist in options
. It's nice and extensible: As soon as you add a new value to defaultOptions
, the loop will copy it into options
, no matter what the callers were passing before.
And, more importantly, that for
loop is really all that jQuery.extend
is doing under the hood: Copying values from one object to another. (The jQuery solution is a little bit more elegant, but I simplified things here to make it more obvious what's going on.)
But what if you want default behavior in some places? For example, if you don't define a specific font size, maybe you just want it to inherit from the parent element or the document rather than having it be assigned to something from defaultOptions
.
If you want that kind of "don't-assign-it-unless-provided" behavior, the same basic pattern above can work, but you need to tweak the default options a little, and then add a condition when you're applying the option. Consider how this example differs from what I showed above:
// Notice that we specifically leave out fontSize here in the defaults. Tooltip.prototype.defaultOptions = { backgroundColor: "#FF9", textColor: "black", animated: false, animationSpeed: 1000 }; Tooltip.prototype.tooltip = function() { for (var i = 0; i < this.targetElement.length; i++) { ... span.style.backgroundColor = this.options.backgroundColor; span.style.color = this.options.textColor; // Now, we only assign the fontSize if it was provided by the user. if (typeof this.options.fontSize !== 'undefined') span.style.fontSize = this.options.fontSize + "px"; ... } }
This hopefully should be enough for you to work with.
Variations on this (the Object.extend
pattern and testing against undefined
) are used all over the place in JavaScript, and are heavily used by jQuery and a whole host of other libraries. If you follow the same basic design they do, you'll be in very good company.
0 comments:
Post a Comment