手写的一个兼容各种浏览器的javascript getStyle函数(获取元素的样式)


Posted in Javascript onJune 06, 2014

要想获取HTML元素的计算样式一直都存在很多的兼容问题,各浏览器都会存在一些差异,Firefox、webkit(Chrome,Safari)支持W3C标准的方法:getComputedStyle(),而IE6/7/8不支持标准的方法但是有私有的属性来实现:currentStyle,IE9和Opera两个都支持。有了这2个方法和属性基本上可以满足大多数要求了。

var getStyle = function( elem, type ){
 return 'getComputedStyle' in window ? getComputedStyle(elem, null)[type] : elem.currentStyle[type];
};

但是对于自适应的宽度和高度使用currentStyle就没法获取到计算的值,只能返回auto,而getComputedStyle()就可以返回计算的值,解决这个问题有好几种办法。我之前想到的是用clientWidth/clientHeight减去padding的值,这样就可以在不支持标准方法的浏览器中获取到计算的宽度和高度。前几天看到司徒正美采用了另一种办法,使用getBoundingClientRect()方法获取到元素在页面中的位置,然后right减去left就是宽度,bottom减去top就是高度。我对他的代码做了一些小小的修改,最终代码如下:

var getStyle = function( elem, style ){
 return 'getComputedStyle' in window ? 
 getComputedStyle( elem, null )[style] : 
 function(){
  style = style.replace( /\-(\w)/g, function( $, $1 ){
   return $1.toUpperCase();
  });
  var val =  elem.currentStyle[style];
  if( val === 'auto' && (style === "width" || style === "height") ){
   var rect =  elem.getBoundingClientRect();
   if( style === "width" ){
    return rect.right - rect.left + 'px';
   }else{
    return rect.bottom - rect.top + 'px';
   }
  }
  return val;
 }();
};
// 调用该方法
var test = document.getElementById( 'test' ),
      // 获取计算的宽度
    tWidth = getStyle( test, 'width' );

新的问题,如果元素的宽度或高度使用了em或%的单位,getComputedStyle()返回的值就会自动将em或%换成px的单位,currentStyle就不会,而如果是font-size使用em为单位,在Opera下返回的是0em,Opera真的很恐怖!

后来在使用发现中还有一些没想到的兼容问题,今天我对原来的代码进行了优化,并对一些常见的兼容问题进行了处理。

在javascript中“-”(中划线或连字符)代表的是减号,而在CSS中,许多样式属性都有这个符号,如padding-left、font-size等,所以在javascript中如果出现如下的代码就一个错误:

elem.style.margin-left = "20px";

正确的写法应该是:
elem.style.marginLeft = "20px";

这里需要把CSS的中划线去掉并把原来紧跟在中划线后的字母大写,俗称“驼峰式”写法,不管是使用javascript设置或是获取元素的CSS样式都应该是驼峰式的写法。但是不少对CSS熟悉而又对javascript不太熟悉的新手朋友总是会犯这种低级错误,使用replace的高级用法可以很简单的将CSS属性中的中划线替换成驼峰式的写法。
var newProp = prop.replace( /\-(\w)/g, function( $, $1 ){
    return $1.toUpperCase();
});

对于float,在javascript中属于保留字,在javascript中设置或获取元素的float的值,都有其他的代替写法,在标准浏览器中为cssFloat,而在IE6/7/8中为styleFloat。

如果top、right、bottom、left没有一个显式的值,在获取这些值的时候部分浏览器会返回一个auto,虽然auto这个值是一个合法的CSS属性值,但绝不是我们想要的结果,而应该是0px。

在IE6/7/8中要设置元素的透明度需要用到滤镜、如:filter:alpha(opacity=60),对于标准浏览器直接设置opacity即可,IE9两种写法都支持,我对获取元素的透明度也做了兼容处理,只要使用opacity就可以获取到所有浏览器元素的透明度的值。

在IE6/7/8中获取元素的宽度和高度已经在上篇文中介绍过了,这里就不再复述了。还有一个需要注意的地方就是,如果元素的样式是使用style内联的写法,或者是已经使用javascript设置过样式的属性,可以使用下面的方法获取到元素的计算样式:

var height = elem.style.height;

这个方法比读取getComputedStyle或currentStyle中的属性值都要快,应该优先使用,当然前提条件就是样式是通过内联的写法设置的(使用javascript设置也是设置内联样式)。优化过的最终代码如下:

var getStyle = function( elem, p ){
 var rPos = /^(left|right|top|bottom)$/,
 ecma = "getComputedStyle" in window,
 // 将中划线转换成驼峰式 如:padding-left => paddingLeft
 p = p.replace( /\-(\w)/g, function( $, $1 ){
 return $1.toUpperCase();
 });
 // 对float进行处理  
 p = p === "float" ? ( ecma ? "cssFloat" : "styleFloat" ) : p; return !!elem.style[p] ? 
 elem.style[p] : 
 ecma ?
 function(){
 var val = getComputedStyle( elem, null )[p];
 // 处理top、right、bottom、left为auto的情况
 if( rPos.test(p) && val === "auto" ){
 return "0px";
 }
 return val;
 }() :
 function(){
 var <a href="http://wirelesscasinogames.com">wirelesscasinogames.com</a> val = elem.currentStyle[p];
 // 获取元素在IE6/7/8中的宽度和高度
  if( (p === "width" || p === "height") && val === "auto" ){
  var rect = elem.getBoundingClientRect();    
  return ( p === "width" ? rect.right - rect.left : rect.bottom - rect.top ) "px";
  }
 // 获取元素在IE6/7/8中的透明度
  if( p === "opacity" ){
  var filter = elem.currentStyle.filter;
  if( /opacity/.test(filter) ){
   val = filter.match( /\d / )[0] / 100;
  return (val === 1 || val === 0) ? val.toFixed(0) : val.toFixed(1);
  }
  else if( val === undefined ){
  return "1";
  }
  }
  // 处理top、right、bottom、left为auto的情况
  if( rPos.test(p) && val === "auto" ){
  return "0px";
  }
  return val;
 }();
};

下面是调用示例:

<style>
.box{
 width:500px;
 height:200px;
 background:#000;
 filter:alpha(opacity=60);
 opacity:0.6;
}
</style>
<div id="box"></div>
<script>
var box = document.getElementById( "box" );
alert( getStyle(box, "width") ); // "500px"
alert( getStyle(box, "background-color") ); // "rgb(0, 0, 0)" / "#000"
alert( getStyle(box, "opacity") ); // "0.6"
alert( getStyle(box, "float") ); // "none"
</script>
Javascript 相关文章推荐
向大师们学习Javascript(视频与PPT)
Dec 27 Javascript
javascript多种数据类型表格排序代码分析
Sep 11 Javascript
IE6下出现JavaScript未结束的字符串常量错误的解决方法
Nov 21 Javascript
JavaScript高级程序设计 客户端存储学习笔记
Sep 10 Javascript
window.parent与window.openner区别介绍
Apr 12 Javascript
jquery仿京东导航/仿淘宝商城左侧分类导航下拉菜单效果
Apr 24 Javascript
javascript对中文按照拼音排序代码
Aug 20 Javascript
基于jquery实现可定制的web在线富文本编辑器附源码下载
Nov 17 Javascript
微信小程序实现图片自适应(支持多图)
Jan 25 Javascript
值得收藏的vuejs安装教程
Nov 21 Javascript
浅谈ajax在jquery中的请求和servlet中的响应
Jan 22 jQuery
vue 使用post/get 下载导出文件操作
Aug 07 Javascript
jquery进行数组遍历如何跳出当前的each循环
Jun 05 #Javascript
js检验密码强度(低中高)附图
Jun 05 #Javascript
原生js编写设为首页兼容ie、火狐和谷歌
Jun 05 #Javascript
js如何判断用户是否是用微信浏览器
Jun 05 #Javascript
如何获取网站icon有哪些可行的方法
Jun 05 #Javascript
IE6中链接A的href为javascript协议时不在当前页面跳转
Jun 05 #Javascript
网页右下角弹出窗体实现代码
Jun 05 #Javascript
You might like
php中让上传的文件大小在上传前就受限制的两种解决方法
2013/06/24 PHP
WordPress中给文章添加自定义字段及后台编辑功能区域
2015/12/19 PHP
js 未结束的字符串常量错误解决方法
2010/06/13 Javascript
window.event快达到全浏览器支持了,以后使用就方便了
2011/11/30 Javascript
用JQuery实现表格隔行变色和突出显示当前行的代码
2012/02/10 Javascript
Ubuntu中搭建Nodejs开发环境过程分享
2014/06/01 NodeJs
Javascript毫秒数用法实例
2015/02/05 Javascript
深入理解JavaScript系列(19):求值策略(Evaluation strategy)详解
2015/03/05 Javascript
JavaScript Array对象详解
2016/03/01 Javascript
原生JavaScript编写canvas版的连连看游戏
2016/05/29 Javascript
JS如何判断json是否为空
2016/07/06 Javascript
基于JavaScript实现新增内容滚动播放效果附完整代码
2017/08/24 Javascript
webstorm添加*.vue文件支持
2018/05/08 Javascript
vue中使用heatmapjs的示例代码(结合百度地图)
2018/09/05 Javascript
angularjs下ng-repeat点击元素改变样式的实现方法
2018/09/12 Javascript
JS继承实现方法及优缺点详解
2020/09/02 Javascript
[01:04:05]VG vs Newbee 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/20 DOTA
[40:53]完美世界DOTA2联赛PWL S3 Magma vs DLG 第二场 12.18
2020/12/20 DOTA
从零学Python之入门(二)基本数据类型
2014/05/25 Python
Python中__init__.py文件的作用详解
2016/09/18 Python
在python中使用xlrd获取合并单元格的方法
2018/12/26 Python
梅尔频率倒谱系数(mfcc)及Python实现
2019/06/18 Python
如何提高python 中for循环的效率
2020/04/15 Python
Python退出时强制运行一段代码的实现方法
2020/04/29 Python
Python读取xlsx数据生成图标代码实例
2020/08/12 Python
python语言time库和datetime库基本使用详解
2020/12/25 Python
美国东北部户外服装和设备零售商:Eastern Mountain Sports
2016/10/05 全球购物
高级护理专业大学生求职信
2013/10/24 职场文书
简单而又朴实的个人求职信分享
2013/12/12 职场文书
出生公证书样本
2014/04/04 职场文书
环保建议书200字
2014/05/14 职场文书
奉献家乡演讲稿
2014/09/13 职场文书
债务追讨授权委托书范本
2014/10/16 职场文书
幼儿园小班开学寄语
2015/05/27 职场文书
导游词之清晏园
2019/11/22 职场文书
使用canvas实现雪花飘动效果的示例代码
2021/03/30 HTML / CSS