【CSS进阶】原生JS getComputedStyle等方法解析

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介:

最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美。

其结构明晰,高内聚、低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷、渐进增强)优雅的处理能力以及 Ajax 等方面周到而强大的定制功能无不令人惊叹。

另外,阅读源码让我接触到了大量底层的知识。对原生JS 、框架设计、代码优化有了全新的认识,接下来将会写一系列关于 jQuery 解析的文章。

我在 github 上关于 jQuery 源码的全文注解,感兴趣的可以围观一下。jQuery v1.10.2 源码注解 

 

言归正传,本文讲的是原生 JS 获取、设置元素最终样式的方法。可能平时框架使用习惯了,以 jQuery 为例,使用 .css() 接口就能便捷的满足我们的要求。再看看今天要讲的 window.getComputedStyle ,就像刚接触 JS 的时候,看到 document.getElementById  一样,名字都这么长,顿生怯意。不过莫慌,我觉得如果我们不是只想做一个混饭吃的前端,那么越是底层的东西,如果能够吃透它,越是能让人进步。

 

    getComputedStyle 与 getPropertyValue 

getComputedStyle 为何物呢,DOM 中 getComputedStyle 方法可用来获取元素中所有可用的css属性列表,以数组形式返回,并且是只读的。IE678 中则用 currentStyle 代替 。

假设我们页面上存在一个 id 为 id 的元素,那么使用 getComputedStyle 获取元素样式就如下图所示:

1
2
3
4
// 语法:
// 在旧版本之前,第二个参数“伪类”是必需的,现代浏览器已经不是必需参数了
// 如果不是伪类,设置为null,
window.getComputedStyle( "元素" "伪类" );

尝试一下之后可以看到,window.getComputedStyle 获取的是所有的样式,如果我们只是要获取单一样式,该怎么做呢。这个时候就要介绍另一个方法 -- getPropertyValue 。

用法也很简单:

1
2
3
// 语法:
// 使用 getPropertyValue 来指定获取的属性
window.getComputedStyle( "元素" "伪类" ).getPropertyValue(style);

 

    IE 下的 currentStyle 与 getAttribute 

说完常规浏览器,再来谈谈老朋友 IE ,与 getComputedStyle 对应,在 IE 中有自己特有的 currentStyle 属性,与 getPropertyValue 对应,IE 中使用 getAttribute 。

和 getComputedStyle 方法不同的是,currentStyle 要获得属性名的话必须采用驼峰式的写法。也就是如果我需要获取 font-size 属性,那么传入的参数应该是 fontSize。因此在IE 中要获得单个属性的值,就必须将属性名转为驼峰形式。

1
2
3
4
5
6
7
8
9
10
11
12
13
// IE 下语法:
// IE 下将 CSS 命名转换为驼峰表示法
// font-size --> fontSize
// 利用正则处理一下就可以了
function  camelize(attr) {
     // /\-(\w)/g 正则内的 (\w) 是一个捕获,捕获的内容对应后面 function 的 letter
     // 意思是将 匹配到的 -x 结构的 x 转换为大写的 X (x 这里代表任意字母)
     return  attr.replace(/\-(\w)/g,  function (all, letter) {
         return  letter.toUpperCase();
     });
}
// 使用 currentStyle.getAttribute 获取元素 element 的 style 属性样式
element.currentStyle.getAttribute(camelize(style));

 

    style 与 getComputedStyle 

必须要提出的是,我们使用 element.style 也可以获取元素的CSS样式声明对象,但是其与 getComputedStyle 方法还是有一些差异的。

首先,element.style 是可读可写的,而 getComputedStyle  为只读。

其次,element.style 只可以获取 style 样式上的属性值,而无法得到所有的 CSS 样式值,什么意思呢?回顾一下 CSS 基础,CSS 样式表的表现有三种方式,

  1. 内嵌样式(inline Style) :是写在 HTML 标签里面的,内嵌样式只对该标签有效。
  2. 内部样式(internal Style Sheet):是写在 HTML 的 <style> 标签里面的,内部样式只对所在的网页有效。
  3. 外部样式表(External Style Sheet):如果很多网页需要用到同样的样式(Styles),将样式(Styles)写在一个以 .CSS 为后缀的 CSS 文件里,然后在每个需要用到这些样式(Styles)的网页里引用这个 CSS 文件。 

而 element.style 只能获取被这些样式表定义了的样式,而 getComputedStyle 能获取到所有样式的值(在不同浏览器结果不一样,chrome 中是 264,在 Firefox 中是238),不管是否定义在样式表中,譬如:

1
2
3
4
5
6
7
8
9
10
11
<style>
#id{
     width : 100px;
     float:left;
}
</style>
 
var  elem = document.getElementById( 'id' );
 
elem.style.length  // 2
window.getComputedStyle(elem,  null ).length  // 264

 

    getComputedStyle 与 defaultView

window.getComputedStyle 还有另一种写法,就是 document.defaultView.getComputedStyle 。

两者的用法完全一样,在 jQuery v1.10.2 中,使用的就是 window.getComputedStyle 。如下

也有特例,查看 stackoverflow ,上面提及到在 Firefox 3.6 ,不使用 document.defaultView.getComputedStyle 会出错。不过毕竟 FF3.6 已经随历史远去,现在可以放心的使用 window.getComputedStyle。

用一张图总结一下:

原生JS获取CSS样式的方法

 

   原生JS实现CSS样式的get与set

说了这么多,接下来将用原生 JS 实现一个小组件,实现 CSS 的 get 与 set,兼容所有浏览器。

完整的组件代码在我的 github 上,戳我直接看代码

getStyle(elem, style)

对于 CSS 的 set ,对于支持 window.getComputedStyle 的浏览器而言十分简单,只需要直接调用。

1
2
3
4
5
6
getStyle:  function (elem, style) {
     // 主流浏览器
     if  (win.getComputedStyle) {
         return  win.getComputedStyle(elem,  null ).getPropertyValue(style);
     }
}

反之,如果是 IE 浏览器,则有一些坑。

opacity 透明度的设定

在早期的 IE 中要设置透明度的话,有两个方法:

  1. alpha(opacity=0.5)
  2. filter:progid:DXImageTransform.Microsoft.gradient( GradientType= 0 , startColorstr = ‘#ccccc’, endColorstr = ‘#ddddd’ );

因此在 IE 环境下,我们需要针对透明度做一些处理。先写一个 IE 下获取透明度的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// IE 下获取透明度   
function  getIEOpacity(elem) {
     var  filter =  null ;
 
     // 早期的 IE 中要设置透明度有两个方法:
     // 1、alpha(opacity=0)
     // 2、filter:progid:DXImageTransform.Microsoft.gradient( GradientType= 0 , startColorstr = ‘#ccccc’, endColorstr = ‘#ddddd’ );
     // 利用正则匹配
     filter = elem.style.filter.match(/progid:DXImageTransform.Microsoft.Alpha\(.?opacity=(.*).?\)/i) || elem.style.filter.match(/alpha\(opacity=(.*)\)/i);
 
     if  (filter) {
         var  value = parseFloat(filter);
         if  (!isNaN(value)) {
             // 转化为标准结果
             return  value ? value / 100 : 0;
         }
     }
     // 透明度的值默认返回 1
     return  1;
}

float 样式的获取

float 属性是比较重要的一个属性,但是由于 float 是 ECMAScript 的一个保留字。(ECMAScript保留字有哪些?戳这里

所以在各浏览器中都会有代替的写法,比如说在标准浏览器中为 cssFloat,而在 IE678 中为 styleFloat 。经测试,在标准浏览器中直接使用 getPropertyValue("float") 也可以获取到 float 的值。而 IE678 则不行,所以针对 float ,也需要一个 HACK。

width | height 样式的获取

然后是元素的高宽,对于一个没有设定高宽的元素而言,在 IE678 下使用 getPropertyValue("width|height") 得到的是 auto 。而标准浏览器会直接返回它的 px 值,当然我们希望在 IE 下也返回 px 值。

这里的 HACK 方法是使用 element.getBoundingClientRect() 方法。

element.getBoundingClientRect() -- 可以获得元素四个点相对于文档视图左上角的值 top、left、bottom、right ,通过计算就可以容易地获得准确的元素大小。

获取样式的驼峰表示法

上文已经提及了,在IE下使用 currentStyle 要获得属性名的话必须采用驼峰式的写法。

OK,需要 HACK 的点已经提完了。那么在 IE 下,获取样式的写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
getStyle:  function (elem, style) {
     // 主流浏览器
     if  (win.getComputedStyle) {
         ...
     // 不支持 getComputedStyle
     else  {
         // IE 下获取透明度
         if  (style ==  "opacity" ) {
             getIEOpacity(elem);
         // IE687 下获取浮动使用 styleFloat
         else  if  (style ==  "float" ) {
             return  elem.currentStyle.getAttribute( "styleFloat" );
                 // 取高宽使用 getBoundingClientRect
         else  if  ((style ==  "width"  || style ==  "height" ) && (elem.currentStyle[style] ==  "auto" )) {
             var  clientRect = elem.getBoundingClientRect();
 
             return  (style ==  "width"  ? clientRect.right - clientRect.left : clientRect.bottom - clientRect.top) +  "px" ;
         }
         // 其他样式,无需特殊处理
         return  elem.currentStyle.getAttribute(camelize(style));
     }
}

setStyle(elem, style, value)

说完 get ,再说说 setStyle ,相较于getStyle ,setStyle 则便捷很多,因为不管是标准浏览器还是 IE ,都可以使用 element.style.cssText 对元素进行样式的设置。

cssText -- 一种设置 CSS 样式的方法,但是它是一个销毁原样式并重建的过程,这种销毁和重建,会增加浏览器的开销。而且在 IE 中,如果 cssText(假如不为空),最后一个分号会被删掉,所以我们需要在其中添加的属性前加上一个 ”;”  。

只是在 IE 下的 opacity 需要额外的进行处理。明了易懂,直接贴代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 设置样式
setStyle:  function (elem, style, value) {
     // 如果是设置 opacity ,需要特殊处理
     if  (style ==  "opacity" ) {
         //IE7 bug:filter 滤镜要求 hasLayout=true 方可执行(否则没有效果)
         if  (!elem.currentStyle || !elem.currentStyle.hasLayout) {
             // 设置 hasLayout=true 的一种方法
             elem.style.zoom = 1;
         }
         // IE678 设置透明度叫 filter ,不是 opacity
         style =  "filter" ;
 
         // !!转换为 boolean 类型进行判断
         if  (!!window.XDomainRequest) {
             value =  "progid:DXImageTransform.Microsoft.Alpha(style=0,opacity="  + value * 100 +  ")" ;
         else  {
             value =  "alpha(opacity="  + value * 100 +  ")"
         }
     }
     // 通用方法
     elem.style.cssText +=  ';'  + (style +  ":"  + value);
}

到这里,原生 JS 实现的 getStyle 与 setStyle 就实现了,完整的代码可以戳这里查看。可以看到,一个简单接口的背后,都是有涉及了很多方面东西。虽然浏览器兼容性是一个坑,但是爬坑的过程却是我们沉淀自己的最好时机。

jQuery 这样的框架可以帮助我们走的更快,但是毫无疑问,去弄清底层实现,掌握原生 JS 的写法,可以让我们走得更远。

 

原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

如果本文对你有帮助,请点下推荐,写文章不容易。

最后,本文组件示例的代码贴在 我的github 上。

我在 github 上关于 jQuery 源码的全文注解,感兴趣的可以围观一下。jQuery v1.10.2 源码注解 

 


本文转自ChokCoco博客园博客,原文链接:http://www.cnblogs.com/coco1s/p/5210667.html

目录
相关文章
|
24天前
|
人工智能
歌词结构的巧妙安排:写歌词的方法与技巧解析,妙笔生词AI智能写歌词软件
歌词创作是一门艺术,关键在于巧妙的结构安排。开头需迅速吸引听众,主体部分要坚实且富有逻辑,结尾则应留下深刻印象。《妙笔生词智能写歌词软件》提供多种 AI 功能,帮助创作者找到灵感,优化歌词结构,写出打动人心的作品。
|
24天前
|
存储 前端开发 JavaScript
JavaScript垃圾回收机制深度解析
【10月更文挑战第21】JavaScript垃圾回收机制深度解析
97 59
|
10天前
|
JSON PHP 数据格式
PHP解析配置文件的常用方法
INI文件是最常见的配置文件格式之一。
|
15天前
|
前端开发 JavaScript
如何在 JavaScript 中访问和修改 CSS 变量?
【10月更文挑战第28天】通过以上方法,可以在JavaScript中灵活地访问和修改CSS变量,从而实现根据用户交互、页面状态等动态地改变页面样式,为网页添加更多的交互性和动态效果。在实际应用中,可以根据具体的需求和场景选择合适的方法来操作CSS变量。
|
6天前
|
缓存 前端开发 JavaScript
优化CSS和JavaScript加载
Next.js和Nuxt.js在优化CSS和JavaScript加载方面提供了多种策略和工具。Next.js通过代码拆分、图片优化和特定的CSS/JavaScript优化措施提升性能;Nuxt.js则通过代码分割、懒加载、预渲染静态页面、Webpack配置和服务端缓存来实现优化。两者均能有效提高应用性能。
|
6天前
|
前端开发 JavaScript
用HTML CSS JS打造企业级官网 —— 源码直接可用
必看!用HTML+CSS+JS打造企业级官网-源码直接可用,文章代码仅用于学习,禁止用于商业
34 1
|
11天前
|
前端开发 JavaScript 安全
HTML+CSS+JS密码灯登录表单
通过结合使用HTML、CSS和JavaScript,我们创建了一个带有密码强度指示器的登录表单。这不仅提高了用户体验,还帮助用户创建更安全的密码。希望本文的详细介绍和代码示例能帮助您在实际项目中实现类似功能,提升网站的安全性和用户友好性。
22 3
|
15天前
|
前端开发 JavaScript UED
如何使用 JavaScript 动态修改 CSS 变量的值?
【10月更文挑战第28天】使用JavaScript动态修改CSS变量的值可以为页面带来更丰富的交互效果和动态样式变化,根据不同的应用场景和需求,可以选择合适的方法来实现CSS变量的动态修改,从而提高页面的灵活性和用户体验。
|
13天前
|
移动开发 前端开发 JavaScript
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
于辰在大学期间带领团队参考网易游戏官网的部分游戏页面,开发了一系列前端实训作品。项目包括首页、2021校园招聘页面和明日之后游戏页面,涉及多种特效实现,如动态图片切换和人物聚合效果。作品源码已上传至CSDN,视频效果可在CSDN预览。
20 0
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
|
17天前
|
机器学习/深度学习 人工智能 安全
TPAMI:安全强化学习方法、理论与应用综述,慕工大、同济、伯克利等深度解析
【10月更文挑战第27天】强化学习(RL)在实际应用中展现出巨大潜力,但其安全性问题日益凸显。为此,安全强化学习(SRL)应运而生。近日,来自慕尼黑工业大学、同济大学和加州大学伯克利分校的研究人员在《IEEE模式分析与机器智能汇刊》上发表了一篇综述论文,系统介绍了SRL的方法、理论和应用。SRL主要面临安全性定义模糊、探索与利用平衡以及鲁棒性与可靠性等挑战。研究人员提出了基于约束、基于风险和基于监督学习等多种方法来应对这些挑战。
37 2

推荐镜像

更多