javascript 精确获取样式属性(上)

JQuery,mootools,Ext等类库在这部分实现得非常艰辛,盘根错节地动用一大堆方法,因此想把这部分抠出来难度很大。深入研究它们的实现后,根据我积累的CSS知识,终于做出一个非常简炼的版本出来。它相当于JQuery.cssCur吧,不过或许功能还丰富一些,按饮食业话说叫“加量不加价”,我的可能还应叫“加量还减价”……版本还处于Beta阶段,由于只个工具函数就不弄成类了。

复制代码 代码如下:


var getStyle = function(el, style){
if(!+"\v1"){
style = style.replace(/\-(\w)/g, function(all, letter){
return letter.toUpperCase();
});
return el.currentStyle[style];
}else{
return document.defaultView.getComputedStyle(el, null).getPropertyValue(style)
}
}


这是函数的最原始状态,由于used value是W3C那边的人搞出来的,因此document.defaultView.getComputedStyle 基本连动也不动就解决百分之99的问题。IE那边的复杂了,虽然微软搞了style,currentStyle与runtimeStyle,但始终都没有一个与getComputedStyle相近的实现,最相近的是currentStyle,它只能取到内部样式,而且我们取值时要把CSS属性转换成驼峰风格。为了方便,我现在再把它分离出来。

复制代码 代码如下:


var camelize = function(attr){
return attr.replace(/\-(\w)/g, function(all, letter){
return letter.toUpperCase();
});
}


接着我们单独解决IE的透明度问题,基本各大类库都是这样做的,可见这问题多么棘手,实在要感谢微软那帮天才:

复制代码 代码如下:


var getIEOpacity = function(el){
var filter;
if(!!window.XDomainRequest){
filter = el.style.filter.match(/progid:DXImageTransform.Microsoft.Alpha\(.?opacity=(.*).?\)/i);
}else{
filter = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
}
if(filter){
var value = parseFloat(filter[1]);
if (!isNaN(value)) {
return value ? value / 100 : 0;
}
}
return 1;
}


这时我们的函数就变成这样:

复制代码 代码如下:


var getStyle = function(el, style){
if(!+"\v1"){
if(style == "opacity"){
return getIEOpacity(el)
}
return el.currentStyle[camelize(style)];
}else{
return document.defaultView.getComputedStyle(el, null).getPropertyValue(style)
}
}


接着下来float属性问题。IE这边是styleFloat,W3C是cssFloat。解决不是问题,不过每次都要转换太麻烦了,我参照Ext的实现把它们缓存起来。

复制代码 代码如下:


var propCache = [];
var propFloat = !+"\v1" ? 'styleFloat' : 'cssFloat';
var camelize = function(attr){
return attr.replace(/\-(\w)/g, function(all, letter){
return letter.toUpperCase();
});
}
var memorize = function(prop) { //意思为:check out form cache
return propCache[prop] || (propCache[prop] = prop == 'float' ? propFloat : camelize(prop));
}
var getIEOpacity = function(el){
//*****************略**********************
}
var getStyle = function (el, style){
if(!+"\v1"){
if(style == "opacity"){
return getIEOpacity(el)
}
return el.currentStyle[memorize(style)];
}else{
if(style == "float"){
style = propFloat;
}
return document.defaultView.getComputedStyle(el, null).getPropertyValue(style)
}
}


到最难的部分了——精确取得高度与宽度。如果用过JQuery的人都知道,John Resig是单独处理这两个属性。其实何止JQuery,其他库都为此头痛。问题的起因是如果没有内联样式或内部样式显式地设置这两个属性,我们在IE下是无法获取它们精确的值,或者获得的是百分比,空字符串,auto,inhert等让人无可奈何的东西。另,对于国人来说,px的地位是远远高于em。总总原因,让我们不能放弃这两个属性。为了取得这两个属性的精确值,我们就需要研究一下CSS继承问题了。我也已撰写相关博文《CSS的inhert与auto》来探讨这问题,没有看,请看完再回来,要不,根本是无法看下去的。
根据CSS的分类,width与height是属性于non-inherited property,由此可知,如果我们不为它设值,默认为auto。这个auto是个神奇的东东,如果是块状元素,它的宽就相当于100%,撑满父元素的内容区,当然这是在不考虑其padding,border与margin的情况下。如果是内联元素,由于不具备盒子模型,你给它设置宽与高是没有意义的,就算在火狐,返回的改过转换的精确值与你看到的情况完全不吻合,如果没有设置,直接返回auto。为了取得以px为单位的精确值,为了屏蔽块状元素与内联元素,我们需要转换思路,不过光盯着CSS属性转。这时,微软做了件好事,开发出offsetXX,clientXX与scrollXX三大家族,现在终于纳入W3C的标准。不过早在这之前,各浏览器已经跟风实现了。
在标准模式中,offsetWidth是包含padding,borderWidth与width,如果存在滚动条,它的offsetWidth也不会变,滚动条的宽度在各浏览器非常一致,都为17px,这时它就会把width减去17px,缺失的空间由滚动条补上。 offsetWidth 如果存在padding与padding,我们就要减去padding与padding 在怪癖模式下,offsetWidth等于width,而width是包含padding与borderWidth。 offsetHeight同理。 clientXX家族好理解,就是不包含borderWidth与滚动条。scrollXX家族不说了,在五大浏览器都不一致。因此,在标准模式中,要取得高与宽,首选clientXX家族,怪癖模式中,首先offsetXX家族。
这时不得不说一下怪癖模式了,别以为升到IE8,设置相应DocType就可以逃过一劫,只要你的网页太多地方不按标准写,IE也转为兼容模式中运作。这兼容模式是否等于怪癖模式就不得而已,因为IE8有多达五种渲染模式,IE5怪癖模式,IE7标准模式,IE8几乎标准模式,IE7兼容模式与支持HTML5的边缘模式。这么多模式,你以为光靠 document.compatMode == "CSS1Compat"能撑住吗?!撑不住的,幸好IE8在添加新模式的同时,又添加了一个 document.documentMode属性,真不知是喜还是悲了。因此判断是否运行于怪癖模式的代码为:

复制代码 代码如下:


var isQuirk = (document.documentMode) ? (document.documentMode==5) ? true :
false : ((document.compatMode=="CSS1Compat") ? false : true);


于是我们有如下伪码:

复制代码 代码如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdpgxy.html