Studied more than a year of JS, also almost write a js library of their own. I’m not writing this as a framework, just a small JS tool Library, so I’m using the name Library. The main collection of some common methods when I write JS, and reference prototype.js, jquery, Google, Baidu, you ah framework.

The main features of this library are:

[Cross-browser] It can be used in the following browsers: IE6, IE7, IE8, Firefox 3.5.3, Chrome 3.0, Safari 4.0.3, Opera 10.10.

Using namespaces is not really a “namespace” of course, just some global variables with similar purposes. Have the following namespaces:? : stands for Object, which holds object-related methods and replaces the most common getElementById method. ? B: indicates Browser, saving the Browser information. ? A: stands for Array, which holds arrays and array-like methods. ? F: stands for Function, save the related methods of Function; ? D: represents Dom, the operations and methods related to the document object; ? E: represents Event, related operations and compatible processing of DOM events; ? CE: stands for CustomEvent, a CustomEvent for a program object; ? S: stands for String, the method to save the String. While I’m not against scaling native objects sparingly, avoid naming pollution if you can. Multiple namespaces (instead of a single one) are simply easier to manage and use. Using two $is not to make more knives (although I would like to), but to avoid conflicts with popular frames. I didn’t use window.x for all variables because that would cause some problems, see here for details.

The use of anonymous functions seems to be a development of jquery, where code is nested inside a function. The idea is to use closures to both use local variables and prevent naming conflicts.

[Using object detection] “Object detection is inherently better than browser detection”, from “PPK on JavaScript” truth. Can use object detection as far as possible, of course, some really difficult do not be too persistent. Object detection jQuery support does a good job, recommend to have a look.

The goals are:

The volume here is not the number of characters, but the number of properties and methods. Library properties and methods must be useful, preferably “mandatory”. Of course the tool library will grow as you use it more, but stick to that principle.

[Efficiency] Efficiency is a constant pursuit, of course, after weighing the pros and cons. In terms of efficiency, I have to admire Google, which not only strives for efficiency in its code, but also downloads code that has already been checked by the browser. Specific can use each browser to download him to see try.

The purpose of establishment is:

[Integration of common methods] common methods to integrate together, not only conducive to code reuse, but also easy to maintain. But it is also inevitable to add extraneous methods, increasing the amount of code and reducing efficiency.

[Solve compatibility problems] Solve some common compatibility problems, reduce the coding burden.

Description of each part

【 Object 】

The namespace is:?

? The most common method in itself: document.getelementByID it also includes the following methods: extend, deepExtend, and Wrapper. Extend is the same as object.extend in prototype.js, and is one of the oldest methods used to extend objects. And deepextend is the same as deep copy, refer to the extend of jQuery.

EmptyFunction saves an emptyFunction and is used to save resources.

Wrapper is a bit more complicated and is mainly used for inheritance. The main reference is $extends (similar to Prototype’s class.create). The Wrapper is a simplified version of $extends, preserving only a few key parts:

O.wrapper = function(me, parent) {
 var ins = function() { me.apply(this, arguments); };
 var subclass = function() {};
 subclass.prototype = parent.prototype;
 ins.prototype = new subclass;
 return ins;
};Copy the code

“Browser”

The namespace is:? B

You can use the userAgent to obtain browser information, including the type and version of the browser. This is basically a reference to the Browser, to understand this part of the first to know the Browser userAgent. Here is the userAgent for each browser (ie series and the latest version of other browsers) :

Ie6 Mozilla / 4.0 (compatible; MSIE 6.0; ...). Ie7 Mozilla / 4.0 (compatible; MSIE 7.0; ...). Ie8 Mozilla / 4.0 (compatible; MSIE 8.0; ...). Ff Mozilla / 5.0 (...). Gecko/20090824 Firefox/3.5.3 Chrome Mozilla/5.0 (...) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.27 Safari/532.0 Safari Mozilla/5.0 (... AppleWebKit/531.9 (KHTML, like Gecko) Version/4.0.3 Safari/531.9.1 Opera/9.80 (...) Presto / 2.2.15 Version / 10.10Copy the code

Determine the browser type by determining the unique character:

var b = { msie: /msie/.test(ua) && ! /opera/.test(ua), opera: /opera/.test(ua), safari: /webkit/.test(ua) && ! /chrome/.test(ua), firefox: /firefox/.test(ua), chrome: /chrome/.test(ua) };Copy the code

Getting version information is a bit tricky, but Browser’s methods are more subtle (with modifications) :

var vMark = ""; for (var i in b) { if (b[i]) { vMark = "safari" == i ? "version" : i; break; } } b.version = vMark && RegExp("(? :" + vMark + ")[\\/: ]([\\d.]+)").test(ua) ? RegExp.$1 : "0";Copy the code

UserAgent = “version”; userAgent = “9.99”; Presto/9.9.9 does not use “version”, it is better not to use “version” in most cases, and this judgment is not used much.

“Array”

The namespace is:? A

The following methods are included: isArray, forEach, map, filter, every, some, indexOf, lastIndexOf

IsArray is used to determine whether an object is an array, indexOf and lastIndexOf are element locating methods, and the others are iterative methods. These custom iteration methods apply not only to arrays, but also to class arrays such as NodeList and arguments, as well as to general objects.

Here I refer to the array extension of Aimin’s Jsenhance.js to integrate the same structure in these custom iterative methods. First we define a basic iteration function each:

function each( object, callback ) { if ( undefined === object.length ){ for ( var name in object ) { if (false === callback( object[name], name, object )) break; } } else { for ( var i = 0, len = object.length; i < len; i++ ) { if (i in object) { if (false === callback( object[i], i, object )) break; }}}};Copy the code

Iterates by index when there is a length attribute (array or class array), otherwise for… In traverses the properties of the object. “Elements that are deleted are not visited” should be used to judge if (I in object). Note that the callback will break out of the loop when it returns false. Using the return value of the callback, you can indirectly control the exit operation inside the callback.

Then prepare the custom iteration method:

each({ forEach: function( object, callback, thisp ){ each( object, function(){ callback.apply(thisp, arguments); }); }, map: function( object, callback, thisp ){ var ret = []; each( object, function(){ ret.push(callback.apply(thisp, arguments)); }); return ret; }, filter: function( object, callback, thisp ){ var ret = []; each( object, function(item){ callback.apply(thisp, arguments) && ret.push(item); }); return ret; }, every: function( object, callback, thisp ){ var ret = true; each( object, function(){ if ( ! callback.apply(thisp, arguments) ){ ret = false; return false; }; }); return ret; }, some: function( object, callback, thisp ){ var ret = false; each( object, function(){ if ( callback.apply(thisp, arguments) ){ ret = true; return false; }; }); return ret; }}Copy the code

Once these methods are defined, we iterate through them with each and add them to the namespace:

When a method is executed, it checks whether the object itself has a specified method. If not, the custom iteration method is used.

each( function(method, name){ ret[name] = function( object, callback, thisp ){ if (object[name]) { return object[name]( callback, thisp ); } else { return method( object, callback, thisp ); }}});Copy the code

【 Function 】

The namespace is:? F

There are now only two methods: bind and bindAsEventListener. These are the prototype.js methods that bind this to function. The principle is to use call/apply to change the object on which the method is called:

var args = slice.call(arguments, 2);
return function() {
return fun.apply(thisp, args.concat(slice.call(arguments)));
}Copy the code

Array.prototype.slice = array.prototype.slice = array.prototype.slice Ps: not only slice, but also concat, join, etc.

BindAsEventListener, unlike Bind, sets the first parameter to an event object, which is used specifically in event callbacks:

var args = slice.call(arguments, 2);
return function(event) {
return fun.apply(thisp, [E.fixEvent(event)].concat(args));
}Copy the code

Fixevents are used to handle event compatibility, as described in the Events section below.

“Dom”

The namespace is:? D

This section is the largest, most complex, and most important part of the toolkit. It mainly stores some Dom operations and resolves general compatibility issues.

GetScrollTop and getScrollLeft are respectively scrollTop and scrollLeft for obtaining document scrolling. In general, you should use documentElement if you are in standard mode, and body otherwise. But Chrome and Safari (both of which use WebKit rendering engines) use body even in standard mode. The method used here is:

var doc = node ? node.ownerDocument : document;
return doc.documentElement.scrollTop || doc.body.scrollTop;Copy the code

Get the documentElement first and then select the body. But this is actually not perfect, if you add the following style to the document:

body{height:300px; overflow:scroll; width:500px; }

In IE6/7, you’ll notice that in standard mode the body part is rendered at the specified height and width, with a scrollbar. This means that documentElement and Body can each set the scrollTop. It’s hard to tell which one to get at this point, but it’s not usually required (at least I haven’t touched it). For a special case like this, it’s ok to know that this is the case, and there’s no need to add too much code for it. Ps: scrollLeft/scrollLeft will not have negative values.

The contains method checks whether the element object of parameter 1 contains the element object of parameter 2. Mainly use ie contains and w3c compareDocumentPosition to judge. See the comparison document location section here for details.

There are two coordinate dependent methods for elements: rect and clientRect. Where rect is the position relative to the browser document and clientRect is the position relative to the browser window. When support getBoundingClientRect, use it with getScrollLeft/getScrollTop for document location. Otherwise, use the offsetLeft/offsetTop loop to get offsetParent. See the comparison element location section here for details.

CurStyle is used to get the final stylesheet of an element, returning getComputedStyle(W3C) or currentStyle(IE), depending on support. Ps: I prefer getComputedStyle because Opera also supports currentStyle.

GetStyle is used to get the final style value of the element’s specified style attribute. Support getComputedStyle and simply use it to get a computed value for the style. For computed Value, see here. CurrentStyle is a little bit like getComputedStyle where you get the final style, but the form of the value you get is different. Unlike getComputedStyle, it does not return an exact uniform size value after rendering, but just a set value. And this value is not necessarily the exact rendered value. The program is mainly done in IE as close as possible to get the getComputedStyle value.

The first step is to handle opacity. Although Ie uses a filter, its value divided by 100 is the same as the value of “opacity” in w3c:

if (/alpha\(opacity=(.*)\)/i.test(style.filter)) {
var opacity = parseFloat(RegExp.$1);
return opacity ? opacity / 100 : 0;
}
return 1;Copy the code

And “float”, which is a little bit easier to do, “styleFloat”.

Another job after getting the style is to convert the units. When the resulting value is determined to be a number in units other than PX, the conversion is performed. The method is based on jQuery’s curCSS. Before understanding, recognize two less used properties: runtimeStyle and pixelLeft.

RuntimeStyle is an IE specific property that is used in much the same way as style, but has the highest precedence. This means that if you set a style in runtimeStyle, the same style in style will be ignored. PixelLeft returns the left Style value of an element in pixels px. PixelLeft returns the left Style of an element in pixels px. Ie (also available in runtimeStyle) and Opera support.

1. Back up the original value:

style = elem.style, left = style.left, rsLeft = elem.runtimeStyle.left;

Set runtimeStyle left to currentStyle left:

elem.runtimeStyle.left = elem.currentStyle.left;

The purpose is to use the runtimeStyle priority to ensure that the changed style will be displayed as the original style. 3, set style left to the value to be converted, and cleverly use pixelLeft to get the value in px units:

style.left = ret || 0;

ret = style.pixelLeft + “px”;

4, restore the left value:

style.left = left;

elem.runtimeStyle.left = rsLeft;

This can be converted to pixel values without changing the render style. This method is also developed by Dean Edwards in jQuery.

Finally, there is a setStyle for setting styles, mainly for batch setting styles and resolving some compatibility issues. Can be called in the following two ways:? D. setstyle (element or collection of elements, {style attribute name: attribute value,… })? D. setstyle (element or set of elements, style attribute name, attribute value) The first argument is the element or set of elements to which the style is to be set. If it is a single element, it is automatically converted to a single element set:

if (! elems.length) { elems = [ elems ]; }Copy the code

The second argument is a collection of key-value pairs, where the key is the style attribute name and the value is the corresponding attribute value. If only one style is set, the second parameter is the style attribute name and the third parameter is the value of the attribute. The program creates a new set of key-value pairs:

if (typeof style == "string") { var s = style; style = {}; style[s] = value; }Copy the code

ForEach is then used to walk through the collection of elements, and the bound function sets all the styles listed in for in for the elements. A single style should be set directly, unless there are compatibility issues.

All that remains is to solve the compatibility problem. First, transparency. Ie uses filters. If you directly set filter, all other filters will be replaced. Get the original filter, replace the transparent filter, and add the transparent filter:

elem.style.filter = (elem.currentStyle.filter || "").replace( /alpha\([^)]*\)/, "" ) +
"alpha(opacity=" + value * 100 + ")";Copy the code

As far as “float” is concerned, ie uses “styleFloat” and others use “cssFloat”.

“Event”

The namespace is:? E

This is an old compatibility issue. There are three methods: addEvent, removeEvent, and fixEvent.

AddEvent and removeEvent are add and remove events respectively. I used ie attachEvent to be compatible with W3C addEventListener. But when I saw Dean Edwards’s method, I switched to his, which, in addition to being more compatible, solved some bugs (see the cloneNode bug section for more details here). The addEvent/removeEvent in the code is modified as needed from the Dean code, but the principle is the same. Also compatible with “mouseEnter” and “mouseleave” events.

Fixevents are used to fix the compatibility of event objects by adding some W3C properties and methods, such as bindAsEventListener. Here, I only make compatibility of IE, and use event directly for other things, so it is not able to make detailed compatibility, but enough is enough. The fix of jQuery is relatively perfect and worth studying.

【 CustomEvent 】

The namespace is:? CE

The above events can only be used for DOM events, but programs sometimes require “custom” events. A CustomEvent is used for custom events in an application.

This is modeled after events, including addEvent and removeEvent, as well as a fireEvent method for manually firing events. Its main use is to add hooks to the program, can add multiple programs at the same time.

“String”

The namespace is:? S

I don’t do much advanced use of strings, so I don’t have any methods to put in at the moment. There is a camelize method that converts a string in the form of a bar (for example, “border-top”) to a hump (for example, “borderTop”). The principle is to use the trick when the second argument of replace is function:

return s.replace(/-([a-z])/ig, function(all, letter) { return letter.toUpperCase(); });

This can be used to convert the style property name, which is used in getStyle/setStyle.

Call way

Finally, the call method is the same as calling a general function method, but with a namespace in front. For example:? .extend(…) Like? Function? C function? D function? (…). Chained calls might be cool, but they’re not really appropriate for a library like this, unless you’re extending native objects (which you’re not using here).

Download Cloudgamer JavaScript Library V0.1 full version compressed version


Cloudgamer JavaScript Library: CloudGamer JavaScript Library V0.1