手写的一个兼容各种浏览器的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 相关文章推荐
js判断浏览器的比较全的代码
Feb 13 Javascript
JS跨域总结
Aug 30 Javascript
jquery parent和parents的区别分析
Oct 02 Javascript
使用JavaScript获取电池状态的方法
May 03 Javascript
Jquery全选与反选点击执行一次的解决方案
Aug 14 Javascript
js获取当前日期时间及其它日期操作汇总
Mar 08 Javascript
ES6学习笔记之map、set与数组、对象的对比
Mar 01 Javascript
vue2.0 循环遍历加载不同图片的方法
Mar 06 Javascript
了解重排与重绘
May 29 Javascript
微信小程序点击列表跳转到对应详情页过程解析
Sep 26 Javascript
javascript 原型与原型链的理解及应用实例分析
Feb 10 Javascript
Node.js中出现未捕获异常的处理方法
Jun 29 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+mysql写的留言本
2006/10/09 PHP
php缓冲 output_buffering的使用详解
2013/06/13 PHP
Json_encode防止汉字转义成unicode的方法
2016/02/25 PHP
thinkPHP5框架实现多数据库连接,跨数据连接查询操作示例
2019/05/29 PHP
Javascript操作select方法大全[新增、修改、删除、选中、清空、判断存在等]
2008/09/26 Javascript
动态改变div的z-index属性的简单实例
2013/08/08 Javascript
jQuery插件jQuery-JSONP开发ajax调用使用注意事项
2013/11/22 Javascript
javascript 事件处理示例分享
2014/12/31 Javascript
JavaScript拖拽、碰撞、重力及弹性运动实例分析
2016/01/08 Javascript
15位和18位身份证JS校验的简单实例
2016/07/18 Javascript
js导出excel文件的简洁方法(推荐)
2016/11/02 Javascript
适用于手机端的jQuery图片滑块动画
2016/12/09 Javascript
Vue.js 2.0 移动端拍照压缩图片上传预览功能
2017/03/06 Javascript
Vue-cli配置打包文件本地使用的教程图解
2018/08/02 Javascript
vue axios数据请求及vue中使用axios的方法
2018/09/10 Javascript
JS+CSS实现随机点名(实例代码)
2019/11/04 Javascript
用jQuery实现抽奖程序
2020/04/12 jQuery
微信小程序12行js代码自己写个滑块功能(推荐)
2020/07/15 Javascript
Element Tooltip 文字提示的使用示例
2020/07/26 Javascript
Vue 按照创建时间和当前时间显示操作(刚刚,几小时前,几天前)
2020/09/10 Javascript
[46:03]LGD vs VGJ.T 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
[01:03:13]VG vs Pain 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
一键搞定python连接mysql驱动有关问题(windows版本)
2016/04/23 Python
Python中模块pymysql查询结果后如何获取字段列表
2017/06/05 Python
Python实现的下载网页源码功能示例
2017/06/13 Python
python pandas.DataFrame选取、修改数据最好用.loc,.iloc,.ix实现
2018/06/11 Python
python画图--输出指定像素点的颜色值方法
2019/07/03 Python
Python实现播放和录制声音的功能
2020/08/12 Python
UI自动化定位常用实现方法代码示例
2020/10/27 Python
Django URL参数Template反向解析
2020/11/24 Python
Hotels.com中国区:好订网
2016/08/18 全球购物
澳大利亚儿童鞋在线:The Trybe
2019/07/16 全球购物
调解员先进事迹材料
2014/02/07 职场文书
《乌塔》教学反思
2014/02/17 职场文书
机械专业求职信范文
2014/07/15 职场文书
人事行政部各岗位职责说明书!
2019/07/15 职场文书