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 相关文章推荐
非主流的textarea自增长实现js代码
Dec 20 Javascript
自定义ExtJS控件之下拉树和下拉表格附源码
Oct 15 Javascript
jQuery获取当前对象标签名称的方法
Feb 07 Javascript
js+css实现有立体感的按钮式文字竖排菜单效果
Sep 01 Javascript
你所未知的3种Node.js代码优化方式
Feb 25 Javascript
javaScript嗅探执行神器-sniffer.js
Feb 14 Javascript
Bootstrap3 多个模态对话框无法显示的解决方案
Feb 23 Javascript
Angular指令之restict匹配模式的详解
Jul 27 Javascript
Vue不能观察到数组length的变化
Jun 08 Javascript
JavaScript new对象的四个过程实例浅析
Jul 31 Javascript
深入解读Node.js中的koa源码
Jun 17 Javascript
vue组件开发之slider组件使用详解
Aug 21 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
CentOS下搭建PHP环境与WordPress博客程序的全流程总结
2016/05/07 PHP
php版微信自动登录并获取昵称的方法
2016/09/23 PHP
PHP获取当前日期及本周一是几月几号的方法
2017/03/28 PHP
PHP多个图片压缩成ZIP的方法
2020/08/18 PHP
js异或加解密效果代码
2008/06/25 Javascript
浅谈JavaScript正则表达式分组匹配
2015/04/10 Javascript
JavaScript实现99乘法表及隔行变色实例代码
2016/02/24 Javascript
javascript实现延时显示提示框特效代码
2016/04/27 Javascript
JS原型链怎么理解
2016/06/27 Javascript
JS中的数组方法笔记整理
2016/07/26 Javascript
JavaScript事件用法浅析
2016/10/31 Javascript
微信小程序 后台https域名绑定和免费的https证书申请详解
2016/11/10 Javascript
使用FormData实现上传多个文件
2018/12/04 Javascript
vue基础之使用get、post、jsonp实现交互功能示例
2019/03/12 Javascript
JavaScript如何判断对象有某属性
2020/07/03 Javascript
详解Python中with语句的用法
2015/04/15 Python
Python扫描IP段查看指定端口是否开放的方法
2015/06/09 Python
python实现百万答题自动百度搜索答案
2018/01/16 Python
Python-OpenCV基本操作方法详解
2018/04/02 Python
Python之time模块的时间戳,时间字符串格式化与转换方法(13位时间戳)
2019/08/12 Python
妙用itchat! python实现久坐提醒功能
2019/11/25 Python
python+selenium+Chrome options参数的使用
2020/03/18 Python
解决keras backend 越跑越慢问题
2020/06/18 Python
如何在Win10系统使用Python3连接Hive
2020/10/15 Python
CSS3使用border-radius属性制作圆角
2014/12/22 HTML / CSS
英国最大的女性服装零售商:Dorothy Perkins
2017/03/30 全球购物
东方通信股份有限公司VC面试题
2014/08/27 面试题
事假请假条范文
2014/04/11 职场文书
妈妈活动方案
2014/08/15 职场文书
公司离职证明标准样本
2014/10/05 职场文书
鲁冰花观后感
2015/06/10 职场文书
2016年师德学习心得体会
2016/01/12 职场文书
大学生心理健康教育心得体会
2016/01/12 职场文书
PHP解决高并发问题
2021/04/01 PHP
python munch库的使用解析
2021/05/25 Python
利用Python+OpenCV三步去除水印
2021/05/28 Python