jquery.fn.css获取当前jQuery所匹配的元素中第一个元素的属性值【$(…).css(cssName),注意这个cssName可以是数组】或给当前jQuery所匹配的每个元素设置样式值【$(…).css(cssname,value) / $(…).css(obj)】;

  可以看见函数内部直接调用了jquery.access来处理。access将当前多个元素组成的jQuery对象所匹配的元素分解成单一元素逐个调用第二个参数中的回调function( elem, name, value );如果参数name是对象的话,access内部分解name递归调用逐个处理name的每一个key/value键值对

  源码

jQuery.fn.css: function( name, value ) {
//access将当前jQuery对象分解成单一元素逐个调用第二个参数中的回调function( elem, name, value ),
//如果参数name是对象的话,access内部分解name递归调用逐个处理name的每一个key/value键值对
return jQuery.access( this, function( elem, name, value ) {
var len, styles,
map = {},
i = 0;
//如果css特征名称是一个数组,比如['left','marginRight']
if ( jQuery.isArray( name ) ) {
styles = getStyles( elem );
len = name.length;
//通过$.css()获取对应的css特征值
for ( ; i < len; i++ ) {
map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
} return map;
} //value有值则调用$.style设置单个css值,value参数无值则通过$.css()获取对应的css特征值
return value !== undefined ?
jQuery.style( elem, name, value ) :
jQuery.css( elem, name );
}, name, value, arguments.length > 1 );
}

  这个api比较简单,但是仔细分析里面所调用的函数会发现一大堆的知识。后面一一来发掘。

  首先我们看到getStyles(elem)这个函数,看一看他的定义

if ( window.getComputedStyle ) {
getStyles = function( elem ) {
return window.getComputedStyle( elem, null );
};
...
//ie8-兼容
} else if ( document.documentElement.currentStyle ) {
getStyles = function( elem ) {
return elem.currentStyle;
};
...
}

  两个不同的方法window.getComputedStyle和elem.currentStyle。接下来一一分析他们。

a. window.getComputedStyle


  完整的表达式window.getComputedStyle(elem,pseudo)

  elem: DOM节点,必须

  pseudo: 伪类,且只能是伪元素的伪类,比如::after,::before,::first-letter,::first-line。可选【Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1) 之前,第二个参数“伪类”是必需的】

  说明:这个函数取出来的是CSS计算后的最终使用的CSS属性值【其中不包括位置关系left/right/top/bottom的属性值,比如left:10%,那么通过getComputedStyle获取的left还是"10%"】(Safari 5.1.7的margin-right返回的是百分比,这个需要特殊处理)。只读。在现代浏览器中支持良好,不支持IE8-

  

  举例说明(这个例子会贯穿全文):

<style>
#myList{
height: 100px;
}
#myList:after{
content: 'a';
height: 100px;
}
</style>

<ul id="myList" style='width:50%;left:666px;'><li>test</li></ul>
<ul id="myList2" style='width:50%;left:111px;'><li>test2</li></ul>

  getComputedStyle的值是计算后的值(比如百分比会转换成像素),实例如下

  

  宽度50%被转换成像素了。

  getComputedStyle中第二个参数只有是伪元素的伪类才起作用,实例如下

  

  如上图可知,只要后面的伪元素不对或没有传递伪元素伪类这个参数,则得到的还是第一个参数对应的元素的getComputedStyle值。上图中.left和.content属性可作证。

  getComputedStyle得到的是一个只读数组对象,数组的每个元素是一个CSS样式名称,并且这个只读数组对象拥有与数组中每个元素一一对应的属性来保存CSS样式的值。我们先看一下结构(window.getComputedStyle(document.getElementById('myList'),null))

  

   

    但是由于不支持IE8-那么我们需要一个IE8能支持的方法。这就是IE自己的东东elem.currentStyle

b. elem.currentStyle


  elem.currentStyle也是一个只读的对象。

  elem.currentStyle与getComputedStyle的不同

  1. elem.currentStyle在IE8-中是一个纯对象,没有类数组的结构,不可以通过style[n]方式获得CSS样式名称;在IE9+中elem.currentStyle才是一个类数组对象。

  2. elem.currentStyle获得的样式虽然是最终的CSS样式,但是并非计算过的样式,比如同样是先前的例子

  getComputedStyle的width结果是像素值632px

  

  而elem.currentStyle的结果是设置的百分比值50%

  

  3. 样式名称的差异,比如对于float属性,IE8-中currentStyle是styleFloat

  

  而firefox中getComputedStyle是cssFloat和float【建议不要使用,浏览器保留,而且也非标准方法,浏览器可以不支持】并存

  

  chrome中getComputedStyle是显示是float,实际上通过float【建议不要使用,浏览器保留,而且也非标准方法,浏览器可以不支持】和cssFloat都可以获取到

  

  

  而IE9是cssFloat和styleFloat都有。

  所以jQuery获取float属性的方式是"float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"

  

c. elem.style


  elem.style和window.getComputedStyle(elem,pseudo)以及elem.currentStyle比较

  elem.style是获取elem的内联样式。这是和window.getComputedStyle(elem,pseudo)以及elem.currentStyle相比不同的地方之一。

  

  style结果可读可写,而getComputedStyle和currentStyle的结果只读。

  style结果是没有计算的结果,这一点和currentStyle类似,getComputedStyle是计算过的结果。如下图中style.width的值是50%,而不是像素值

  

  

d. 现代浏览器获取样式表中某个样式的值--getPropertyValue


  getPropertyValue(className)是现代浏览器(IE9+,firefox,chrome...)样式表的一个属性方法。所以只要是现代浏览器,上面getComputedStyle/currentStyle/style三种方式获取的样式表style都可以使用该方法获取样式值。例如style.getPropertyValue("float")。

  需要注意的是className是直接属性名称(比如"background-color")。是“float”而非“css-float”或“cssFloat”。

  

  如果是使用属性获取的方式获取float值,则需要转换成"cssFloat"或"styleFloat",比如

  

  这个比较折腾。

  

  而由于IE8-又不支持该方法,IE8-直接使用属性获取方式

  

  

  IE8-的currentStyle还支持另一种获取属性方法:style.getAttribute(className)。

  需要注意的是className是可以是直接属性名称或是驼峰写法(比如"background-color"或“backgroundColor"都可以)。

  

  所以,我们为了兼容的话,有两种处理样式的方法

  1. 结合getPropertyValue(className)和getAttribute(className)使用,因为他们两className都可以是直接属性名称

  2. 使用属性获取方式style[className]但是需要注意的是属性名称需要兼容,比如:"float"需要替换成"cssFloat"或"styleFloat"。

  而jQuery的处理就是选择第二种方式。

  说道这里,虽然jQuery使用第二种方式,但是有一个属性使用属性方式获取会失败,这就是奇葩的"filter"属性。这个属性必须使用getPropertyValue才能获取正确

  用表格总结一下CSS属性获取的相关用法

特点 getComputedStyle currentStyle style
浏览器支持情况 IE9+,chrome,firefox... IE ALL
可读可写 只读 只读 可读可写
是否为计算最终值(比如百分比、比例都计算为真实的像素值)
(外部样式表+内部样式表+内联样式)的最终结果 否(只是内联样式)
属性获取方式style.name和style[name] 支持("filter"属性除外) 支持 支持
支持的获取CSS属性值的方法 getPropertyValue IE8-只支持getAttribute;IE9+支持getPropertyValue和getAttribute("filter") IE8-只支持getAttribute;IE9+支持getPropertyValue和getAttribute("filter");其他浏览器只支持getPropertyValue
突出优点 标准化,支持伪元素(如::after),获取的是计算后的结果   可读可写
       

  这一章字数已经不少了,我先前还以为这一章会比较简单的,没有想到拓展开来这么多!骚年们,耐心看下去。。。

  接下来继续分析源码:

  既然了解了各种获取CSS样式表的方法,接下来看一个获取指定的CSS样式名称对应的计算值得函数curCSS = function( elem, name, _computed ) 。难点在于通过currentStyle和getComputedStyle获取到的值可能是百分比或相对值得时候,我们需要进行模拟计算出真实的值。过程比较点单,看源码注释

//备注:我们在window.getComputedStyle包含了"window"
//因为node.js中的js DOM如果没有他的话将被终止
if ( window.getComputedStyle ) {
getStyles = function( elem ) {
return window.getComputedStyle( elem, null );
};   curCSS = function( elem, name, _computed ) {
    var width, minWidth, maxWidth,
    computed = _computed || getStyles( elem ),
    // getPropertyValue只有在IE9的 .css('filter')中用到
    ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
    style = elem.style;     if ( computed ) {
      if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
        ret = jQuery.style( elem, name );
      }
      // Chrome < 17 and Safari 5.0使用"计算结果"替代"使用的值"来计算margin-right
      // Safari 5.1.7 (最新)返回百分比但是我们需要像素值,这一点违背CSSOM草案
      //http://dev.w3.org/csswg/cssom/#resolved-values
      //模拟计算
      if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
        //保存原值
        width = style.width;
        minWidth = style.minWidth;
        maxWidth = style.maxWidth;         //放入新的值来获得计算值,比如marginRight为10%的时候,通过放入width为10%,然后通过computed.width即可获得10%对应的px宽度
        style.minWidth = style.maxWidth = style.width = ret;
        ret = computed.width;         //还原更改的值
        style.width = width;
        style.minWidth = minWidth;
        style.maxWidth = maxWidth;
      }
    }
    return ret;
  }; //低版本ie兼容
} else if ( document.documentElement.currentStyle ) {
getStyles = function( elem ) {
return elem.currentStyle;
}; curCSS = function( elem, name, _computed ) {
var left, rs, rsLeft,
computed = _computed || getStyles( elem ),
ret = computed ? computed[ name ] : undefined,
style = elem.style; //这里避免给ret设置空字符
//所以我们不默认为”auto”
if ( ret == null && style && style[ name ] ) {
ret = style[ name ];
} // 我们对以奇怪结尾的数字(比如1em)要把他转化成像素
// 但是不能是位置属性,应为他们是和父元素成比例的,并且我们不能测量父元素的比例,因为他可能是一大堆比例堆叠而成(比如<div style=’left:10%’><p style=’left:20%’><span style=’left:20%’></span></p></div>),根本无法计算
if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
//保存原值
left = style.left;
rs = elem.runtimeStyle;
rsLeft = rs && rs.left; //放入新的值来获得计算值
if ( rsLeft ) {
rs.left = elem.currentStyle.left;
}
style.left = name === "fontSize" ? "1em" : ret;
ret = style.pixelLeft + "px"; //还原更改的值
style.left = left;
if ( rsLeft ) {
rs.left = rsLeft;
}
} return ret === "" ? "auto" : ret;
};
}

  根据jQuery.fn.css函数最后的处理

return value !== undefined ?
jQuery.style( elem, name, value ) :
jQuery.css( elem, name );

  可知css处理的两个关键低级api:jQuery.style和jQuery.css。

  前面已经分析了只有.style是可读可写的,同理,这里的jQuery.style作用也是用来读写内联样式的。jQuery.style的处理流程为

  1.修正css特征名称保存为origName,真正能被浏览器识别的名称保存为name。

  2.查找name或origName的cssHooks。

  3.如果是设置值(有传递value参数),则设置之。其中比较特殊的处理是value可以是累计字符串(如:“+=”)需要先通过jQuery.css取出原来的值来计算。如果value是数字,需要根据情况看是否添加“px”单位。如果是有相应的cssHooks也要特殊处理等等。

  4.如果是获取值(没有传递value参数),分两种情况,有hooks通过hooks获取,否则直接style[name]即可。

  源码

//给DOM节点设置或获取样式特征值
jQuery.style: function( elem, name, value, extra ) {
//文本和注释节点不能设置样式特征值
if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
return;
} //修正css特征名称以适配当前浏览器
var ret, type, hooks,
origName = jQuery.camelCase( name ),
style = elem.style;
//jQuery.cssProps缓存查询过的css特征名称供后续便捷查找使用
name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); //获取有前缀版本的hooks或没有前缀版本的hooks
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; //如果是给css特征名称设置值
if ( value !== undefined ) {
type = typeof value; // convert relative number strings (+= or -=) to relative numbers. #7345
//rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" )
//转换相对数字符串+=/-=为相应的数字
if ( type === "string" && (ret = rrelNum.exec( value )) ) {
//(+ + 1) == 1;(- + 1) == -1
value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
// Fixes bug #9237
type = "number";
} //NaN和null不可用
if ( value == null || type === "number" && isNaN( value ) ) {
return;
} //除开不可设置为像素单位的css特征,其他的都添加上“px”
if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
value += "px";
} //support.clearCloneStyle = div.style.backgroundClip === "content-box";
//div.style.backgroundClip为非“content-box”模式且
//设置的值为空的background...将其设置为继承父节点样式
// Fixes #8908, 更准确的做法是对每一个问题特征都设置默认值,但是这至少会调用8次函数
if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
style[ name ] = "inherit";
} //如果提供了hook则使用hook设置值,否则设置置顶的值
if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { //当要设置的值为无效值的时候ie会抛出异常
// Fixes bug #5509
try {
style[ name ] = value;
} catch(e) {}
}
//获取值
} else {
//如果提供了hook则使用hook取值
if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
return ret;
} // 其他情况从style对象中取值
return style[ name ];
}
} //返回一个css特征名称,该名称可能是供应商添加了前缀的特征名
function vendorPropName( style, name ) {
//短名称未添加厂商前缀
if ( name in style ) {return name; } //检查供应商的前缀名
//cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]
var capName = name.charAt(0).toUpperCase() + name.slice(1),
origName = name,
i = cssPrefixes.length; while ( i-- ) {
name = cssPrefixes[ i ] + capName;
if ( name in style ) {return name; }
} return origName;
}

  

  jQuery.css处理也比较简单

  1.修正css特征名称保存为origName,真正能被浏览器识别的名称保存为name

  2.如果存在相应的cssHooks,则处理之;否则使用curCSS方法获取样式值

  3.对获取到的样式值做一些默认值得处理,比如css样式fontWeight的默认值为“normal”对应的值应该是400。

  源码

//获取name对应的css特征值
css: function( elem, name, extra, styles ) {
var num, val, hooks,
origName = jQuery.camelCase( name ); //修正名称
name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); //获取有前缀版本的hooks或没有前缀版本的hooks
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; //从hook中提取值
if ( hooks && "get" in hooks ) {
val = hooks.get( elem, true, extra );
} //其他情况使用curCSS取值
if ( val === undefined ) {
val = curCSS( elem, name, styles );
} //cssNormalTransform = {letterSpacing: 0,fontWeight: 400}
//将"normal"转化成计算值
if ( val === "normal" && name in cssNormalTransform ) {
val = cssNormalTransform[ name ];
} //当强制或提供了限定和val看上去像数字时强制转化成数字并返回
if ( extra === "" || extra ) {
num = parseFloat( val );
return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
}
return val;
}

  

  OK,这一章终于搞定了。

  如果觉得本文不错,请点击右下方【推荐】!

  

  

  

jQuery-1.9.1源码分析系列(九) CSS操作的更多相关文章

  1. jQuery源码分析系列(38) : 队列操作

    Queue队列,如同data数据缓存与Deferred异步模型一样,都是jQuery库的内部实现的基础设施 Queue队列是animate动画依赖的基础设施,整个jQuery中队列仅供给动画使用 Qu ...

  2. jQuery 2.0.3 源码分析 钩子机制 - 属性操作

    jQuery提供了一些快捷函数来对dom对象的属性进行存取操作. 这一部分还是比较简单的. 根据API这章主要是分解5个方法 .attr()   获取匹配的元素集合中的第一个元素的属性的值  或 设置 ...

  3. jQuery源码分析系列

    声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...

  4. [转]jQuery源码分析系列

    文章转自:jQuery源码分析系列-Aaron 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAaro ...

  5. jQuery源码分析系列(转载来源Aaron.)

    声明:非本文原创文章,转载来源原文链接Aaron. 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAa ...

  6. jQuery源码分析系列——来自Aaron

    jQuery源码分析系列——来自Aaron 转载地址:http://www.cnblogs.com/aaronjs/p/3279314.html 版本截止到2013.8.24 jQuery官方发布最新 ...

  7. jquery2源码分析系列

    学习jquery的源码对于提高前端的能力很有帮助,下面的系列是我在网上看到的对jquery2的源码的分析.等有时间了好好研究下.我们知道jquery2开始就不支持IE6-8了,从jquery2的源码中 ...

  8. jQuery-1.9.1源码分析系列完毕目录整理

    jQuery 1.9.1源码分析已经完毕.目录如下 jQuery-1.9.1源码分析系列(一)整体架构 jQuery-1.9.1源码分析系列(一)整体架构续 jQuery-1.9.1源码分析系列(二) ...

  9. MyCat源码分析系列之——结果合并

    更多MyCat源码分析,请戳MyCat源码分析系列 结果合并 在SQL下发流程和前后端验证流程中介绍过,通过用户验证的后端连接绑定的NIOHandler是MySQLConnectionHandler实 ...

  10. MyCat源码分析系列之——SQL下发

    更多MyCat源码分析,请戳MyCat源码分析系列 SQL下发 SQL下发指的是MyCat将解析并改造完成的SQL语句依次发送至相应的MySQL节点(datanode)的过程,该执行过程由NonBlo ...

随机推荐

  1. outline (group) 在Excel worksheet 中

    Group按钮的作用就是使Excel能展示一个轮廓,将明晰列折上,只显示公式的结果列. 在代码中实现的方法: 用worksheet的get_range选中明晰columns的某行单元格,然后调用这个r ...

  2. perl 删除过期文件

    #!/usr/bin/perl `find /bak/ >list.txt`; open LIST,"/root/list.txt"; while (<LIST> ...

  3. 阿里聚安全受邀参加SFDC安全大会,分享互联网业务面临问题和安全创新实践

    现今,技术引领的商业变革已无缝渗透入我们的日常生活,「技术改变生活」的开发者们被推向了创新浪潮的顶端.国内知名的开发者技术社区 SegmentFault 至今已有四年多了,自技术问答开始,他们已经发展 ...

  4. Python黑帽编程2.1 Python编程哲学

    Python黑帽编程2.1  Python编程哲学 本节的内容有些趣味性,涉及到很多人为什么会选择Python,为什么会喜欢这门语言.我带大家膜拜下Python作者的Python之禅,然后再来了解下P ...

  5. 剑指Offer面试题:22.二叉搜索树的后序遍历序列

    一.题目:二叉搜索树的后序遍历序列 题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则返回true,否则返回false.假设输入的数组的任意两个数字都互不相同. 例如在下面 ...

  6. CSharpGL(0)一个易学易用的C#版OpenGL

    +BIT祝威+悄悄在此留下版了个权的信说: CSharpGL(0)一个易学易用的C#版OpenGL CSharpGL是我受到SharpGL的启发,在整理了SharpGL,GLM,SharpFont等开 ...

  7. java中 用telnet 判断服务器远程端口是否开启

    package net.jweb.common.util; import java.io.BufferedReader; import java.io.BufferedWriter; import j ...

  8. Laravel5.0学习--03 Artisan命令

    本文以laravel5.0.22为例. 简介 Artisan 是 Laravel 内置的命令行接口.它提供了一些有用的命令协助您开发,它是由强大的 Symfony Console 组件所驱动.利用它, ...

  9. Oracle 超长字符串分割劈分

    Oracle 超长字符串分割劈分,具体能有多长没测过,反正很大.... 下面,,,,直奔主题了: CREATE OR REPLACE FUNCTION splitstr(p_string IN clo ...

  10. 修改HTML5 input placeholder 颜色及修改失效的解决办法

    input::input-placeholder{color: #bdbdbd ;} /* 有些资料显示需要写,有些显示不需要,但是在编辑器webstorm中该属性不被识别 */ ::-webkit- ...