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 相关文章推荐
禁止js文件缓存的代码
Apr 09 Javascript
jquery实现网站超链接和图片提示效果
Mar 21 Javascript
js给onclick赋值传参数的两种方法
Nov 25 Javascript
jquery dialog open后,服务器端控件失效的快速解决方法
Dec 19 Javascript
js中document.write使用过程中的一点疑问解答
Mar 20 Javascript
jQuery插件cxSelect多级联动下拉菜单实例解析
Jun 24 Javascript
BootStrap入门教程(二)之固定的内置样式
Sep 19 Javascript
JavaScript常用工具方法封装
Feb 12 Javascript
一些手写JavaScript常用的函数汇总
Apr 16 Javascript
vuex 中插件的编写案例解析
Jun 10 Javascript
深入学习TypeScript 、React、 Redux和Ant-Design的最佳实践
Jun 17 Javascript
JS如何使用剪贴板操作Clipboard API
May 17 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开启安全模式后禁用的函数集合
2011/06/26 PHP
PHP可变函数的使用详解
2013/06/14 PHP
PHP实现基于文本的摩斯电码生成器
2016/01/11 PHP
php实现微信分享朋友链接功能
2019/02/18 PHP
java解析json方法总结
2019/05/16 PHP
使用javascript做的一个随机点名程序
2014/02/13 Javascript
浅谈jQuery事件绑定原理
2015/01/02 Javascript
JS通过ajax动态读取xml文件内容的方法
2015/03/24 Javascript
JavaScript将字符串转换为整数的方法
2015/04/14 Javascript
Winform客户端向web地址传参接收参数的方法
2016/05/17 Javascript
使用UrlConnection实现后台模拟http请求的简单实例
2017/01/04 Javascript
详解Vue使用命令行搭建单页面应用
2017/05/24 Javascript
原生js中ajax访问的实例详解
2017/09/19 Javascript
在 Node.js 中使用 async 函数的方法
2017/11/17 Javascript
angularJs-$http实现百度搜索时的动态下拉框示例
2018/02/27 Javascript
详解webpack 打包文件体积过大解决方案(code splitting)
2018/04/10 Javascript
浅谈React的最大亮点之虚拟DOM
2018/05/29 Javascript
详解Angularjs 自定义指令中的数据绑定
2018/07/19 Javascript
基于vue循环列表时点击跳转页面的方法
2018/08/31 Javascript
Postman的下载及安装教程详解
2018/10/16 Javascript
JavaScript遍历数组和对象的元素简单操作示例
2019/07/09 Javascript
express框架中使用jwt实现验证的方法
2019/08/25 Javascript
对Layer弹窗使用及返回数据接收的实例详解
2019/09/26 Javascript
基于vue--key值的特殊用处详解
2020/07/31 Javascript
[01:51]DAC趣味视频-如何成为职业选手.mp4
2017/04/02 DOTA
详解python中的 is 操作符
2017/12/26 Python
五分钟带你搞懂python 迭代器与生成器
2020/08/30 Python
python脚本使用阿里云slb对恶意攻击进行封堵的实现
2021/02/04 Python
如何转换一个字符串到enum值
2014/04/12 面试题
乡镇办公室工作决心书
2014/03/11 职场文书
大学生全国两会报告感想
2014/03/17 职场文书
伦敦奥运会口号
2014/06/13 职场文书
护士实习求职信
2014/06/22 职场文书
防灾减灾宣传标语
2014/10/07 职场文书
从np.random.normal()到正态分布的拟合操作
2021/06/02 Python
《进击的巨人》新联动CM 兵长强势出击兽巨人
2022/04/05 日漫