JavaScript 工具库 Cloudgamer JavaScript Library v0.1 发布


Posted in Javascript onOctober 29, 2009

主要集合了我写js时一些常用的方法,并参考了prototype.js,jquery,google,百度,有啊等框架。

工具库已经在近几个效果中使用:
JavaScript 多级联动浮动菜单 (第二版) 
JavaScript 浮动定位提示效果 
JavaScript Table行定位效果 
JavaScript Table排序

这个工具库的主要特点是:

【跨浏览器】
能在以下浏览器使用:IE6,IE7,IE8,Firefox 3.5.3,Chrome 3.0,Safari 4.0.3,Opera 10.10
ie系列是必须的,其他能支持最新版本就够了。

【使用命名空间】
当然不是真正“命名空间”,只是一些全局变量,用途相似而已。
有如下命名空间:
$$:代表Object,保存对象相关方法,也代替最常用的getElementById方法;
$$B:代表Browser,保存浏览器信息;
$$A:代表Array,保存数组和类数组的相关方法;
$$F:代表Function,保存函数的相关方法;
$$D:代表Dom,文档对象的相关操作和方法;
$$E:代表Event,事件的相关操作和兼容处理;
$$S:代表String,保存字符串的相关方法。
虽然我不反对有节制地扩展原生对象,但可以的话还是避免命名污染吧。
用多个命名空间(而不用单个)只因管理容易,用起来方便。
用两个$,不是要更多美刀(虽然很想),而是避免跟流行的框架冲突。
使用全部变量时我没有用window.x的形式,因为那样会导致一些问题,具体参考这里

【使用匿名函数】
貌似是jquery发扬光大的,就是把代码嵌在一个function里面。
其实就是利用闭包,一来可以使用局部变量,二来可以防止命名冲突。

【使用对象检测】
“对象检测天生地优于浏览器检测”,出自“ppk谈JavaScript”的真理。
能用对象检测的都尽量用,当然有些实在太难搞的也不要太执着。
对象检测方面jQuery的support做的很好,建议去看一下。

追求目标是:

【小体积】
这里的体积不是说字符的多少,而是属性和方法的数量。
工具库的属性和方法必须是很有用的,最好是“不得不加”的。
当然随着使用的增加,工具库也会慢慢的扩大,但要坚持这个原则。

【高效率】
高效是不变的追求,当然是在权衡利弊之后。
说到高效不得不佩服一下google,它不但代码追求效率,而且下载的代码是已经经过浏览器检测的。
具体可以自己用各个浏览器下载看看试试。

建立目的是:

【整合常用方法】
把常用的方法整合到一起,既利于代码复用,也便于维护。
但也不可避免地添加一些无关的方法,从而增加了代码量,降低了效率。

【解决兼容问题】
解决一些常见的兼容性问题,减轻编码负担。

各个部分说明

【Object】

命名空间是:$$

$$本身就是最常用的方法:document.getElementById
它还包括两个方法:extend和deepextend。
其中extend跟prototype.js的Object.extend是一样的,用来扩展对象,是用得最久的方法之一了。
而deepextend是深度扩展,这里的深度跟深度复制里面的意思差不多,参考的是jQuery的extend。

【Browser】

命名空间是:$$B

通过userAgent获取浏览器信息,主要获取浏览器的类型和版本。
这里基本是参考有啊的Browser,要了解这部分首先要知道各浏览器的userAgent。
下面是各浏览器的userAgent(除了ie其他是目前最新版):
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
Opera/9.80 (...) Presto/2.2.15 Version/10.10

先通过判断特有字符来判断浏览器类型:

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)
};

获取版本信息就比较麻烦,有啊Browser的方法就比较巧妙(有修改):

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

但参考上面的userAgent会发现opera的获取应该也是用"version"才对啊,问题是它在10之前的userAgent是这样的:
Opera/9.99 (...) Presto/9.9.9
并没有用"version",为了适用大部分情况还是不要用"version"好了,而且这个判断用的也不多。

【Array】

命名空间是:$$A

里面包括以下方法:
isArray:判断对象是否数组
forEach:对数组中的每个元素都执行一次指定的函数(callback)。(参考地址
filter:对数组中的每个元素都执行一次指定的函数(callback),并且创建一个新的数组,该数组元素是所有回调函数执行时返回值为 true 的原数组元素。(参考地址
every:对数组中的每个元素都执行一次指定的函数(callback),直到此函数返回 false,如果发现这个元素,every 将返回 false,如果回调函数对每个元素执行后都返回 true ,every 将返回 true。(参考地址
some:对数组中的每个元素都执行一次指定的函数(callback),直到此函数返回 true,如果发现这个元素,some 将返回 true,如果回调函数对每个元素执行后都返回 false ,some 将返回 false。(参考地址
map:对数组中的每个元素都执行一次指定的函数(callback),并且以每次返回的结果为元素创建一个新数组。(参考地址
indexOf:比较 searchElement 和数组的每个元素是否绝对一致(===),当有元素符合条件时,返回当前元素的索引。如果没有发现,就直接返回 -1 。(参考地址
lastIndexOf:比较 searchElement 和数组的每个元素是否绝对一致(===),当有元素符合条件时,返回当前元素的索引。如果没有发现,就直接返回 -1 。(参考地址

以上方法除了isArray,都是JavaScript 1.6里数组增加的方法,具体可以去mozilla查看。

不止数组能使用这些方法,只要对象能像数组那样历遍就能使用,例如NodeList对象,arguments对象。

【Function】

命名空间是:$$F

里面现在只有两个方法:bind和bindAsEventListener。
这两个是prototype.js里面的经典方法了,是用来给function绑定this的。
原理是利用call/apply改变调用方法的对象。
其中用到Array.prototype.slice把arguments对象转成数组,不知道是谁发现的,知道这个用法就行了。
ps:不止slice,其他像concat,join等也能这样使用。

bindAsEventListener跟bind不同的是会把第一个参数设定为event对象,专门用在事件回调函数中。
其中用到fixEvent处理event的兼容性,后面Event的部分会详细说明。

【Dom】

命名空间是:$$D

这部分是工具库中最大,最复杂也最重要的部分。
主要是储存了一些Dom操作,并解决一般的兼容性问题。

其中getScrollTop和getScrollLeft分别是获取文档滚动的scrollTop和scrollLeft。
一般来说如果在标准模式下应该用documentElement获取,否则用body获取。
但chrome和safari(都是用WebKit渲染引擎)即使在标准模式下也要用body来获取。
这里用的方法是:

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

优先获取documentElement的再选择body的,这样就基本能解决了。
但这个其实是不完善的,如果给文档添加如下样式:

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

在ie6/7会发现在标准模式下body的部分会按指定高度和宽度呈现,而且能带滚动条。
就是说documentElement和body能各自设置scrollTop。
那这个时候该获取哪个就说不清了,还好一般情况并不需要这样设置的(至少我是没碰过)。
对于这样的特例,知道有这个情况就行了,没必要为了它增加太多代码。
ps:获取的scrollLeft/scrollLeft是不会有负值的。

contains方法是判断参数1元素对象是否包含了参数2元素对象。
主要利用ie的contains和w3c的compareDocumentPosition来判断。
具体参考这里的比较文档位置部分

有两个元素坐标相关的方法:rect和clientRect。
其中rect是相对浏览器文档的位置,clientRect是相对浏览器视窗的位置。
当支持getBoundingClientRect时,利用它配合getScrollLeft/getScrollTop获取文档位置。
否则用循环获取offsetParent的offsetLeft/offsetTop的方式获取。
具体参考这里的比较元素位置部分

还有三个样式相关的方法:curStyle、getStyle、setStyle
curStyle是用来获取元素的最终样式表的,根据支持情况返回getComputedStyle(w3c)或currentStyle(ie)。
ps:这里要优先判断getComputedStyle,因为opera也支持currentStyle。

getStyle是用来获取元素指定样式属性的最终样式值的。
支持getComputedStyle的直接用它获取样式的computed value就行,关于computed value可以参考这里
而currentStyle虽然跟getComputedStyle有点像都是获取最终样式,但两者得到的值的形式是不同的。
它不像getComputedStyle那样返回渲染完成后准确的规格统一的值,而只是一个设置值。
而且这个值还不一定就是渲染后的准确值。
程序主要做的就是在ie中尽量获取接近getComputedStyle的值。

首先是处理透明度,ie虽然用的是滤镜但它的值除以100就跟w3c的"opacity"的值一样了: 

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

还有"float",这个比较简单换成"styleFloat"就行了。

获取样式后还有一个工作是转换单位。当判断得到的值是一个数值而单位又不是px的话,就会进行转换。
方法是参考jQuery的curCSS的,理解之前先认识两个比较少用的属性:runtimeStyle和pixelLeft。

runtimeStyle是ie特有的属性,用法跟style差不多,但它有着最高的优先级。
就是说如果在runtimeStyle设置了样式就会忽略掉style中同样的样式。
具体可以参考birdshome的“关于HTML Object中三个Style实例的区别”和“关于使用runtimeStyle属性问题讨论
而pixelLeft的作用是以像素px为单位返回元素的left样式值,ie(还能用在runtimeStyle)和opera支持。

知道这两个东西后,就能理解它的原理了:
1,先备份原来的值:

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

2,设置runtimeStyle的left为currentStyle的left:

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

目的是利用runtimeStyle的优先级保证修改style后能按原来的样式显示;
3,设置style的left为要转换的值,并巧妙地利用pixelLeft获取这个值的px单位形式:

style.left = ret || 0;
ret 
= style.pixelLeft + "px";

4,最后恢复原来的left值:

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

这样就能在不改变渲染样式的情况下转换成像素值了。
ps:jQuery中有说明这个方法也是Dean Edwards提出的,神啊。

最后还有一个setStyle用来设置样式,主要用来批量设置样式和解决一些兼容问题。
可以用以下两种方式的调用:
$$D.setStyle(元素或元素集合, { 样式属性名: 属性值, ... })
$$D.setStyle(元素或元素集合, 样式属性名, 属性值)
第一个参数是要设置样式的元素或元素集合,如果是单个元素会自动转成单元素集合:

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

第二个参数是一个键值对集合,键是样式属性名,值是对应的属性值。
如果只设置一个样式,可以设第二个参数是样式属性名,第三个参数是属性值,由程序新建一个键值对集合:

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

再用forEach历遍元素集合,绑定的函数里给元素设置用for in列出的所有样式。
ps:单个元素设置单个样式应该直接设置,除非是有兼容问题。

剩下的就是解决兼容问题了。
首先是透明度,ie是用滤镜的,如果直接设置filter会把其他滤镜都替换没了。
参考jQuery的方法,先获取原来的filter,替换掉透明滤镜的部分,再加上要设置好的透明滤镜:

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

挺巧妙的方法,记得值要乘以100对应w3c的"opacity"。

至于"float"就比较简单,ie用"styleFloat"其他用"cssFloat"就行了。

【Event】

命名空间是:$$E

这个是兼容性的老问题了,这里包含三个方法:addEvent,removeEvent,fixEvent。

addEvent和removeEvent分别是添加和移除事件,以前我是用ie的attachEvent跟w3c的addEventListener做兼容。
但看到Dean Edwards的方法后,就改用他的了,除了兼容性更好外还能解决一些bug(详细看这里的cloneNode的bug部分)。
代码中的addEvent/removeEvent根据需要在Dean代码的基础上做了些修改,不过原理还是一样的。

而fixEvent是用来修正event对象的兼容性的,主要是添加一些w3c的属性和方法,上面bindAsEventListener就用到了它。
这里我只做了ie的兼容,其他都是直接使用event,这样就做不到细致的兼容,不过够用就行了。
jQuery的fix就做的比较完善,值得研究。

【String】

命名空间是:$$S

我比较少做String的高级应用,所以暂时也没什么方法需要放进来。
里面有一个camelize方法,用来把横杠形式的字符串(例如"border-top")转换成驼峰形式(例如"borderTop")。
原理是利用replace第二个参数是function时的技巧:

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

这个可以用在样式属性名的转换,在getStyle/setStyle中就使用了它。

调用方式

最后说说调用方式,跟调用一般函数方法是一样的,只是前面要带上命名空间。
例如:$$.extend(...)
像$$由于本身就是function,可以直接这样用:$$(...)
链式调用或许比较酷,但不太适合用在这样的工具库上,除非是扩展原生对象(这里也没有使用)。
完整代码

/*! 
* Cloudgamer JavaScript Library v0.1 
* Copyright (c) 2009 cloudgamer 
* Blog: http://cloudgamer.cnblogs.com/ 
* Date: 2009-10-29 
*/ var $$, $$B, $$A, $$F, $$D, $$E, $$S; 
(function(){ 
var O, B, A, F, D, E, S; 

/*Object*/ 
O = function (id) { return "string" == typeof id ? document.getElementById(id) : id; }; 
O.extend = function (destination, source) { 
for (var property in source) { 
destination[property] = source[property]; 
} 
return destination; 
}; 
O.deepextend = function (destination, source) { 
for (var property in source) { 
var copy = source[property]; 
if ( destination === copy ) continue; 
if ( typeof copy === "object" ){ 
destination[property] = arguments.callee( destination[property] || {}, copy ); 
}else{ 
destination[property] = copy; 
} 
} 
return destination; 
}; 

/*Browser*/ 
/*from youa*/ 
B = (function(ua){ 
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) 
}; 
var vMark = ""; 
for (var i in b) { 
if (b[i]) { 
vMark = i; 
} 
} 
if (b.safari) { 
vMark = "version"; 
} 
b.version = RegExp("(?:" + vMark + ")[\\/: ]([\\d.]+)").test(ua) ? RegExp.$1 : "0"; 
b.ie = b.msie; 
b.ie6 = b.msie && parseInt(b.version) == 6; 
b.ie7 = b.msie && parseInt(b.version) == 7; 
b.ie8 = b.msie && parseInt(b.version) == 8; 
return b; 
})(window.navigator.userAgent.toLowerCase()); 

/*Array*/ 
A = { 
isArray: function( obj ) { 
return Object.prototype.toString.call(obj) === "[object Array]"; 
}, 
forEach: function( array, callback, thisp ){ 
if (array.forEach) { 
array.forEach(callback, thisp); 
} else { 
for ( var i = 0, len = array.length; i < len; i++ ) { 
callback.call( thisp, array[i], i, array ); 
} 
} 
}, 
filter: function( array, callback, thisp ){ 
if (array.filter) { 
return array.filter(callback, thisp); 
} else { 
var res = []; 
for ( var i = 0, len = array.length; i < len; i++ ) { 
callback.call( thisp, array[i], i, array ) && res.push(array[i]); 
}; 
return res; 
} 
}, 
every: function( array, callback, thisp ){ 
if (array.every) { 
return array.every(callback, thisp); 
} else { 
for ( var i = 0, len = array.length; i < len; i++ ) { 
if ( !callback.call( thisp, array[i], i, array ) ) return false; 
}; 
return true; 
} 
}, 
some: function( array, callback, thisp ){ 
if (array.some) { 
return array.some(callback, thisp); 
} else { 
for ( var i = 0, len = array.length; i < len; i++ ) { 
if ( callback.call( thisp, array[i], i, array ) ) return true; 
}; 
return false; 
} 
}, 
map: function( array, callback, thisp ){ 
if (array.map) { 
return array.map(callback, thisp); 
} else { 
var res = []; 
for ( var i = 0, len = array.length; i < len; i++ ) { 
res.push( callback.call( thisp, array[i], i, array ) ); 
}; 
return res; 
} 
}, 
indexOf: function( array, elt ){ 
if (array.indexOf) { 
return array.indexOf(elt); 
} else { 
for ( var i = 0, len = array.length; i < len; i++ ) { 
if ( array[i] === elt ) return i; 
}; 
return -1; 
} 
}, 
lastIndexOf: function( array, elt, from ){ 
if (array.lastIndexOf) { 
return array.lastIndexOf(elt); 
} else { 
var len = array.length; 
if ( isNaN(from) || from >= len - 1 ) { 
from = len - 1; 
} else { 
from = from < 0 ? Math.ceil(from) + len : Math.floor(from); 
} 
for ( ; from > -1; from-- ) { if ( array[i] === elt ) return i; }; 
return -1; 
} 
} 
}; 

/*Function*/ 
F = (function(){ 
var slice = Array.prototype.slice; 
return { 
bind: function( fun, thisp ) { 
var args = slice.call(arguments, 2); 
return function() { 
return fun.apply(thisp, args.concat(slice.call(arguments))); 
} 
}, 
bindAsEventListener: function( fun, thisp ) { 
var args = slice.call(arguments, 2); 
return function(event) { 
return fun.apply(thisp, [E.fixEvent(event)].concat(args)); 
} 
} 
}; 
})(); 

/*Dom*/ 
D = { 
getScrollTop: function(node){ 
var doc = node ? node.ownerDocument : document; 
return doc.documentElement.scrollTop || doc.body.scrollTop; 
}, 
getScrollLeft: function(node){ 
var doc = node ? node.ownerDocument : document; 
return doc.documentElement.scrollLeft || doc.body.scrollLeft; 
}, 
contains: function(a, b){ 
return (this.contains = a.compareDocumentPosition 
? function(a, b){ return !!(a.compareDocumentPosition(b) & 16); } 
: function(a, b){ return a != b && a.contains(b); } 
)(a, b); 
}, 
rect: function(node){ 
var left = 0, top = 0, right = 0, bottom = 0; 
//ie8的getBoundingClientRect获取不准确 
if ( !node.getBoundingClientRect || B.ie8 ) { 
var n = node; 
while (n) { left += n.offsetLeft, top += n.offsetTop; n = n.offsetParent; }; 
right = left + node.offsetWidth; bottom = top + node.offsetHeight; 
} else { 
var rect = node.getBoundingClientRect(); 
left = right = this.getScrollLeft(node); top = bottom = this.getScrollTop(node); 
left += rect.left; right += rect.right; 
top += rect.top; bottom += rect.bottom; 
}; 
return { "left": left, "top": top, "right": right, "bottom": bottom }; 
}, 
clientRect: function(node){ 
var rect = this.rect(node), sLeft = this.getScrollLeft(node), sTop = this.getScrollTop(node); 
rect.left -= sLeft; rect.right -= sLeft; 
rect.top -= sTop; rect.bottom -= sTop; 
return rect; 
}, 
curStyle: function(elem){ 
return (this.curStyle = document.defaultView 
? function(elem){ return document.defaultView.getComputedStyle(elem, null); } 
: function(elem){ return elem.currentStyle; } 
)(elem); 
}, 
getStyle: function(elem, name){ 
return (this.getStyle = document.defaultView 
? function(elem, name){ 
var style = document.defaultView.getComputedStyle(elem, null); 
return name in style ? style[ name ] : style.getPropertyValue( name ); 
} 
: function(elem, name){ 
var style = elem.currentStyle; 
//透明度 from youa 
if (name == "opacity") { 
if (/alpha\(opacity=(.*)\)/i.test(style.filter)) { 
var opacity = parseFloat(RegExp.$1); 
return opacity ? opacity / 100 : 0; 
} 
return 1; 
}; 
if (name == "float") { name = "styleFloat"; } 
var ret = style[ name ] || style[ S.camelize( name ) ]; 
//单位转换 from jqury 
if ( !/^\-?\d+(px)?$/i.test( ret ) && /^\-?\d/.test( ret ) ) { 
style = elem.style, left = style.left, rsLeft = elem.runtimeStyle.left; 
elem.runtimeStyle.left = elem.currentStyle.left; 
style.left = ret || 0; 
ret = style.pixelLeft + "px"; 
style.left = left; 
elem.runtimeStyle.left = rsLeft; 
} 
return ret; 
} 
)(elem, name); 
}, 
setStyle: function(elems, style, value) { 
if (!elems.length) { elems = [ elems ]; } 
if (typeof style == "string") { var s = style; style = {}; style[s] = value; } 
A.forEach(elems, function(elem){ 
for (var name in style) { 
var value = style[name]; 
if (name == "opacity" && B.ie) { 
//ie透明度设置 from jqury 
elem.style.filter = (elem.currentStyle.filter || "").replace( /alpha\([^)]*\)/, "" ) + 
"alpha(opacity=" + value * 100 + ")"; 
} else if (name == "float") { 
elem.style[ B.ie ? "styleFloat" : "cssFloat" ] = value; 
} else { 
elem.style[ S.camelize( name ) ] = value; 
} 
}; 
}); 
} 
}; 

/*Event*/ 
E = (function(){ 
/*from dean edwards*/ 
var addEvent, removeEvent, guid = 1; 
if ( window.addEventListener ) { 
addEvent = function(element, type, handler){ 
element.addEventListener(type, handler, false); 
}; 
removeEvent = function(element, type, handler){ 
element.removeEventListener(type, handler, false); 
}; 
} else { 
addEvent = function(element, type, handler){ 
if (!handler.$$guid) handler.$$guid = guid++; 
if (!element.events) element.events = {}; 
var handlers = element.events[type]; 
if (!handlers) { 
handlers = element.events[type] = {}; 
if (element["on" + type]) { 
handlers[0] = element["on" + type]; 
} 
} 
handlers[handler.$$guid] = handler; 
element["on" + type] = handleEvent; 
}; 
removeEvent = function(element, type, handler){ 
if (element.events && element.events[type]) { 
delete element.events[type][handler.$$guid]; 
} 
}; 
function handleEvent() { 
var returnValue = true, event = fixEvent(); 
var handlers = this.events[event.type]; 
for (var i in handlers) { 
this.$$handleEvent = handlers[i]; 
if (this.$$handleEvent(event) === false) { 
returnValue = false; 
} 
} 
return returnValue; 
}; 
} 
function fixEvent(event) { 
if (event) return event; 
event = window.event; 
event.pageX = event.clientX + D.getScrollLeft(); 
event.pageY = event.clientY + D.getScrollTop(); 
event.target = event.srcElement; 
event.stopPropagation = stopPropagation; 
event.preventDefault = preventDefault; 
if(event.type == "mouseout") { 
event.relatedTarget = event.toElement; 
}else if(event.type == "mouseover") { 
event.relatedTarget = event.fromElement; 
} 
return event; 
}; 
function stopPropagation() { this.cancelBubble = true; }; 
function preventDefault() { this.returnValue = false; }; 
return { 
"addEvent": addEvent, 
"removeEvent": removeEvent, 
"fixEvent": fixEvent 
}; 
})(); 

/*String*/ 
S = { 
camelize: function(s){ 
return s.replace(/-([a-z])/ig, function(all, letter) { return letter.toUpperCase(); }); 
} 
}; 
/*System*/ 
// remove css image flicker 
if (B.ie6) { 
try { 
document.execCommand("BackgroundImageCache", false, true); 
} catch(e) {} 
}; 
/**/ 
$$ = O; $$B = B; $$A = A; $$F = F; $$D = D; $$E = E; $$S = S; 
})();

打包下载
Javascript 相关文章推荐
从零开始学习jQuery (三) 管理jQuery包装集
Feb 23 Javascript
基于jquery &amp; json的省市区联动代码
Jun 26 Javascript
js中onload与onunload的使用示例
Aug 25 Javascript
在jquery中的ajax方法怎样通过JSONP进行远程调用
Apr 04 Javascript
js的for in循环和java里foreach循环的区别分析
Jan 28 Javascript
使用jquery.qrcode.min.js实现中文转化二维码
Mar 11 Javascript
原生js制作日历控件实例分享
Apr 06 Javascript
原生js实现弹出层登录拖拽功能
Dec 05 Javascript
解决vue热替换失效的根本原因
Sep 19 Javascript
Windows下支持自动更新的Electron应用脚手架的方法
Dec 24 Javascript
浅谈对于react-thunk中间件的简单理解
May 01 Javascript
浅探express路由和中间件的实现
Sep 30 Javascript
JScript 脚本实现文件下载 一般用于下载木马
Oct 29 #Javascript
javascript 面向对象,实现namespace,class,继承,重载
Oct 29 #Javascript
javascript实现的距离现在多长时间后的一个格式化的日期
Oct 29 #Javascript
jQuery 判断元素上是否绑定了事件
Oct 28 #Javascript
Firebug 字幕文件JSON地址获取代码
Oct 28 #Javascript
jquery 选择器部分整理
Oct 28 #Javascript
JavaScript 全角转半角部分
Oct 28 #Javascript
You might like
PHP小技巧搜集,每个PHPer都来露一手
2007/01/02 PHP
基于php使用memcache存储session的详解
2013/06/25 PHP
php入门教程之Zend Studio设置与开发实例
2016/09/09 PHP
PHP批量删除jQuery操作
2017/07/23 PHP
PHP 实现页面静态化的几种方法
2017/07/23 PHP
关于laravel 数据库迁移中integer类型是无法指定长度的问题
2019/10/09 PHP
JQuery 学习笔记 选择器之六
2009/07/23 Javascript
关于extjs treepanel复选框选中父节点与子节点的问题
2013/04/02 Javascript
基于datagrid框架的查询
2013/04/08 Javascript
一个实用的图片切换支持点击切换和自动轮播
2014/09/09 Javascript
js使用递归解析xml
2014/12/12 Javascript
网页从弹窗页面单选框传值至父页面代码分享
2015/09/29 Javascript
在线引用最新jquery文件的实现方法
2016/08/26 Javascript
vue实现nav导航栏的方法
2017/12/13 Javascript
在React项目中使用Eslint代码检查工具及常见问题
2018/10/10 Javascript
微信小程序实现保存图片到相册功能
2018/11/30 Javascript
vue 检测用户上传图片宽高的方法
2020/02/06 Javascript
Vue之封装公用变量以及实现方式
2020/07/31 Javascript
用Python实现服务器中只重载被修改的进程的方法
2015/04/30 Python
python 处理dataframe中的时间字段方法
2018/04/10 Python
pyshp创建shp点文件的方法
2018/12/31 Python
我们为什么要减少Python中循环的使用
2019/07/10 Python
matplotlib图例legend语法及设置的方法
2020/07/28 Python
CSS3 选择器 基本选择器介绍
2012/01/21 HTML / CSS
*p++ 自增p 还是p所指向的变量
2016/07/16 面试题
修理厂厂长岗位职责
2014/01/30 职场文书
《鱼游到了纸上》教学反思
2014/02/20 职场文书
2014年母亲节演讲稿范文
2014/05/07 职场文书
党在我心中演讲稿
2014/09/02 职场文书
出差报告怎么写
2014/11/06 职场文书
2014年办公室个人工作总结
2014/11/12 职场文书
故宫的导游词
2015/01/31 职场文书
运动会通讯稿200字
2015/07/20 职场文书
2015年初中教师个人工作总结
2015/07/21 职场文书
python基础入门之字典和集合
2021/06/13 Python
Redis 的查询很快的原因解析及Redis 如何保证查询的高效
2022/03/16 Redis