首页 » 编写高质量代码:改善JavaScript程序的188个建议 » 编写高质量代码:改善JavaScript程序的188个建议全文在线阅读

《编写高质量代码:改善JavaScript程序的188个建议》建议130:从CSS样式表中抽取元素尺寸

关灯直达底部

每个元素的显示属性都存储在CSS样式表中,如果能够从中读取元素的width和height属性,就可以精确地获得它的大小。在JavaScript中访问和设置元素的CSS属性,可以通过元素的style属性进行。style是一个集合对象,它内部包含很多CSS脚本属性。例如,使用style属性设置元素的显示宽度,并读取该宽度值:


var p=document.getElementsByTagName(/"p/")[0];

p.style.;

var w=p.style.width;//返回字符串/"100px/"


但是,在JavaScript中设置或读取CSS属性值时,都必须包含单位,并且传递或返回的值都是字符串,同时通过这种方式获得的信息往往是不准确的,因为style属性中并不包含元素的样式属性的默认值。例如,在样式表或行内样式中未显式定义p元素的宽度,根据它的默认值(即auto值),实际宽度显示为100%。此时,如果使用元素的style属性读取width值,则返回空字符串。


<p></p>

<script language=/"javascript/"type=/"text/javascript/">

var p=document.getElementsByTagName(/"p/")[0];

alert(p.style.width);//返回空字符串

</script>


由于不同浏览器之间不兼容,获取元素最终样式的属性还需要针对不同的浏览器分别设计,开发者应该考虑IE与支持DOM标准的浏览器存在不同的处理方法。

首先,自定义一个扩展函数来兼容IE和DOM的实现方法。扩展函数的参数为当前元素(即e)和它的属性名(即n),函数返回值为该元素的样式的属性值。注意,这里的属性名是遵循驼峰命名法定义的CSS脚本属性名。代码如下:


//获取指定元素的样式属性值

//参数:e表示具体的元素,n表示要获取元素的脚本样式的属性名,如/"width/"、/"borderColor/"

//返回值:返回该元素e的样式属性n的值

function getStyle(e,n){

if(e.style[n]){

return e.style[n];

}

else if(e.currentStyle){

return e.currentStyle[n];

}

else if(document.defaultView&&document.defaultView.getComputedStyle){

n=n.replace(/([A-Z])/g,/"-$1/");

n=n.toLowerCase;

var s=document.defaultView.getComputedStyle(e,null);

if(s)

return s.getPropertyValue(n);

}

else

return null;

}


DOM标准在读取CSS属性值时的规定比较特殊,它遵循CSS语法规则中的约定来命名属性名,即在复合属性名中使用连字符来连接多个单词,而不是遵循驼峰命名法,利用首字母大写的方式来区分不同的单词。例如,属性borderColor在传递给DOM时就需要转换为border-color,否则就会错判。因此,传递的参数名还需要进行转换,不过利用正则表达式可以轻松实现。下面调用这个扩展函数来获取指定元素的实际宽度:


<p></p>

<script language=/"javascript/"type=/"text/javascript/">

var p=document.getElementsByTagName(/"p/")[0];

var w=getStyle(p,/"width/");//调用扩展函数,返回字符串/"auto/"

</script>


如果为p元素显式定义200像素的宽度:


<p></p>


则调用扩展函数getStryle后会返回字符串“200px”:


var w=getStyle(p,/"width/");//调用扩展函数,返回字符串/"200px/"


虽然,我们知道auto值等于父元素的宽度,但是这只有通过人工计算才能够获取。例如,下面的示例中嵌套的结构就比较复杂,中间包含多层元素,并且宽度取值都是百分比,只需简单的口算过程就可以知道,最内层元素的宽度的实际值为25像素。


<p >

<p >

<p >

<p >

<p></p>

</p>

</p>

</p>

</p>


设计一个简单的迭代计算,使用getStyle扩展函数抽取每层元素的宽度值,然后把百分比转换为数值,之后相乘即可。例如:


var p1=document.getElementsByTagName(/"p/")[0];

var w1=parseInt(getStyle(p1,/"width/"));

var p2=document.getElementsByTagName(/"p/")[1];

var w2=parseInt(getStyle(p2,/"width/"))/100;

var p3=document.getElementsByTagName(/"p/")[2];

var w3=parseInt(getStyle(p3,/"width/"))/100;

var p4=document.getElementsByTagName(/"p/")[3];

var w4=parseInt(getStyle(p4,/"width/"))/100;

var w=w1*w2*w3*w4;//返回数值25


上面的方法虽然很直接,但是比较简陋,缺乏灵活性。下面设计一个扩展函数fromStyle,该函数对getStyle扩展函数的功能进行补充。设计fromStyle函数的参数为要获取尺寸的元素,以及利用getStyle函数所得到的值,然后返回这个元素的具体尺寸值(即为具体的数字)。代码如下:


//把fromStyle函数返回值转换为实际的值

//参数:e表示具体的元素,w表示元素的样式属性值,通过getStyle函数获取,p表示当前元素百分比转换为小数的值,以便在上级元素中计算当前元素的尺寸

//返回值:返回具体的数字值

function fromStyle(e,w,p){

var p=arguments[2];

if(!p)p=1;

if(/px/.test(w)&&parseInt(w))return parseInt(parseInt(w)*p);

else if(/%/.test(w)&&parseInt(w)){//如果元素宽度值为百分比值

var b=parseInt(w)/100;

if((p!=1)&&p)b*=p;

e=e.parentNode;

if(e.tagName==/"BODY/")throw new Error(/"整个文档结构都没有定义固定尺寸,没法计算了,请使用其他方法获取尺寸./");

w=getStyle(e,/"width/");

return arguments.callee(e,w,b);

}

else if(/auto/.test(w)){

var b=1;

if((p!=1)&&p)b*=p;

e=e.parentNode;

if(e.tagName==/"BODY/")throw new Error(/"整个文档结构都没有定义固定尺寸,没法计算了,请使用其他方法获取尺寸./");

w=getStyle(e,/"width/");

return arguments.callee(e,w,b);

}

else

throw new Error(/"元素或其父元素的尺寸定义了特殊的单位./");

}


最后,针对上面的嵌套结构,调用该函数就可以直接计算出元素的实际值:


var p=document.getElementById(/"p/");

var w=getStyle(p,/"width/");

w=fromStyle(p,w);//返回数值25


要获取元素的高度值,在getStyle函数中修改第二个参数值为字符串“height”即可。