提前阅读:点击打开链接
(1)源码分析如下:
<pre name="code" class="javascript">jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
//{padding:innerHeight,content:height,"":outerHeight}
//{padding:innerWidth,content:width,"":outerWidth}
jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
// margin is only for outerHeight, outerWidth
//funcName是innerHeight,height,outerHeight,defaultExtra是padding,content,""
//funcName是innerWidth,width,outerWidth,defaultExtra是padding,content,""
jQuery.fn[ funcName ] = function( margin, value ) {
//每一个函数接受两个参数margin,value。如果不传入参数那么chainable为false
var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
//exta默认是defaultExtra
extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
//调用底层的access方法
return jQuery.access( this, function( elem, type, value ) {
var doc;
//如果是DOM是window那么获取window.document.documentElement("clientWidth")
if ( jQuery.isWindow( elem ) ) {
// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
// isn't a whole lot we can do. See pull request at this URL for discussion:
// https://github.com/jquery/jquery/pull/764
return elem.document.documentElement[ "client" + name ];
}
// Get document width or height
//如果DOM是document那么首先获取documentElement,返回document.body.scrollWidth,document.scrollWidth,
//document.body.offsetWidth,document.offsetWidth和document.clientWidth最大值!
if ( elem.nodeType === 9 ) {
doc = elem.documentElement;
// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
// unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
return Math.max(
elem.body[ "scroll" + name ], doc[ "scroll" + name ],
elem.body[ "offset" + name ], doc[ "offset" + name ],
doc[ "client" + name ]
);
}
//如果value是undefined,表示获取数据,调用jQuery.css完成,否则调用jQuery.style完成
return value === undefined ?
// Get width or height on the element, requesting but not forcing parseFloat
jQuery.css( elem, type, extra ) :
// Set width or height on the element
jQuery.style( elem, type, value, extra );
}, type, chainable ? margin : undefined, chainable, null );
};
});
});
//调用方式1:
//innerWidth如果没有传入参数表示获取属性,底层调用access方法
//alert($("#content").innerWidth());
//调用方式2:
//把宽度设为150px,chinable是true,传入access的value是150px
//在access里面调用fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
//表示fn表示上面的回调函数,fn(elems[i],"width","150")第一个表示DOM元素
//$("#content").innerWidth(150);
//调用方式3:把innerWidth至少设置为1000
//这时候margin是函数,chainable是padding,传入access的margin是函数。也就是key是函数
//在access里面raw是false,调用为 fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
//第一步:调用fn,就是上面access里面的第二个参数函数,传入DOM和key="width"也就是获取每一个DOM的width值
//第二步:根据获取的值调用我们自己的为innerWidth传入的参数函数,上下文为DOM,第一个参数是DOM下标,第二个参数是该元素的width值!
//第三步:把调用的结果再次调用access的第二个函数参数,第一个参数是DOM,第二个参数是"width",第三个参数是第二步返回的值,这时候value不是空,表示设置!
//$("#content").innerWidth(function(index,innerWidth){
// return Math.max(innerWidth, 1000);
//})
alert($("#content").outerWidth());
总结:
(1)如果DOM是document那么首先获取documentElement,然后返回document.body.scrollWidth,document.scrollWidth,document.body.offsetWidth,document.offsetWidth和document.clientWidth最大值!
(2)两层each函数的关系图为:
(3)根据后面的jQuery.css的源码分析知道这里的defaultExtra要么为空字符串要么就是非空,所以都会经过parseFloat操作!如果parseFloat之后是Number类型那么就返回number值,否则返回初始值!
vendorPropName源码:
var cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
function vendorPropName( style, name ) {
// shortcut for names that are not vendor prefixed
if ( name in style ) {
return name;
}
//将name首字母大写,同时用origName保存没有首字母大写之前的名字
// check for vendor prefixed names
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;
}
//打印[object CSSStyleDeclaration]
//alert($("#content")[0].style);
alert(vendorPropName($("#content")[0].style,"-webkit-border-radius"));
jQuery.cssHooks源码:
cssHooks: {
opacity: {
get: function( elem, computed ) {
if ( computed ) {
// We should always get a number back from opacity
var ret = curCSS( elem, "opacity" );
return ret === "" ? "1" : ret;
}
}
}
}
jQuery.cssProps源码:
cssProps: {
// normalize float css property
"float": support.cssFloat ? "cssFloat" : "styleFloat"
}
jQuery.cssNormalTransform源码:
cssNormalTransform = {
letterSpacing: "0",//如果letterSpacing是normal那么设置为0
fontWeight: "400"//如果font-weight是normal,那么把它设置为400
}
curCss源码:
<pre name="code" class="javascript">//如果window有getComputedStyle方法
if ( window.getComputedStyle ) {
getStyles = function( elem ) {
// Support: IE<=11+, Firefox<=30+ (#15098, #14150)
// IE throws on elements created in popups
// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
if ( elem.ownerDocument.defaultView.opener ) {
return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
}
//返回[object CSSStyleDeclaration]
return window.getComputedStyle( elem, null );
};
//调用:val = curCSS( elem, name, styles );
curCSS = function( elem, name, computed ) {
var width, minWidth, maxWidth, ret,
style = elem.style;
computed = computed || getStyles( elem );
//如果getComputedStyle返回值存在那么继续调用getPropertyValue就可以了,在IE9
//中直接用下标调用可以了,如果getComputedStyle不存在,那么返回undefined
// getPropertyValue is only needed for .css('filter') in IE9, see #12537
ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;
if ( computed ) {
//如果获取到的属性值为空字符串同时该元素所在的文档不包括自身,那么调用jQuery.style
if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
ret = jQuery.style( elem, name );
}
// A tribute to the "awesome hack by Dean Edwards"
// Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
// Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
//var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
//var rmargin = (/^margin/);
//chrome<17和Safari5特殊处理,通过调用getComputedStyle获取元素的cssDeclaration对象,然后获取该对象的width
if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
// Remember the original values
//记住原始的width,minWidth,maxWidh
width = style.width;
minWidth = style.minWidth;
maxWidth = style.maxWidth;
//对minWidth,maxWidth,width赋值为新值,该值通过getComputedStyle方法获取到
// Put in the new values to get a computed value out
style.minWidth = style.maxWidth = style.width = ret;
ret = computed.width;
// Revert the changed values
style.width = width;
style.minWidth = minWidth;
style.maxWidth = maxWidth;
}
}
// Support: IE
// IE returns zIndex value as an integer.
return ret === undefined ?
ret :
ret + "";
};//End of curCss function
//如果getComputedStyle不存在,那么判断document.documentElement.currentStyle
} else if ( document.documentElement.currentStyle ) {
//用元素的currentStyle就可以了!
getStyles = function( elem ) {
return elem.currentStyle;
};
//调用:val = curCSS( elem, name, styles );
curCSS = function( elem, name, computed ) {
var left, rs, rsLeft, ret,
style = elem.style;
//获取到currentStyle对象(注意,第三个参数可以直接传入style对象作为computed)
computed = computed || getStyles( elem );
//如果currentStyle存在,获取属性值
ret = computed ? computed[ name ] : undefined
// Avoid setting ret to empty string here
// so we don't default to auto
//元素的style对象存在,style的name属性值存在,但是currentStyle相关属性不存在
//那么把结果赋值为style对象的相关属性!
if ( ret == null && style && style[ name ] ) {
ret = style[ name ];
// From the awesome hack by Dean Edwards
// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
// If we're not dealing with a regular pixel number
// but a number that has a weird ending, we need to convert it to pixels
// but not position css attributes, as those are proportional to the parent element instead
// and we can't measure the parent instead because it might trigger a "stacking dolls" problem
//var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
//var rmargin = (/^margin/);
if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
// Remember the original values
left = style.left;
rs = elem.runtimeStyle;
rsLeft = rs && rs.left;
// Put in the new values to get a computed value out
if ( rsLeft ) {
rs.left = elem.currentStyle.left;
}
style.left = name === "fontSize" ? "1em" : ret;
ret = style.pixelLeft + "px";
// Revert the changed values
style.left = left;
if ( rsLeft ) {
rs.left = rsLeft;
}
}
// Support: IE
// IE returns zIndex value as an integer.
return ret === undefined ?
ret :
ret + "" || "auto";
};
}
curCss方法总结:
(1)获取元素的style属性,如果window上有getComputedStyle就直接调用,但是调用的时候为了支持IE<11,FF<30+我们会判断elem.ownerDocument.defaultView.opener是否存在,存在就调用elem.ownerDocument.defaultView.getComputedStyle方法
(2)currentStyle
是IE浏览器自娱自乐的一个属性,其与element.style
可以说是近亲,至少在使用形式上类似,element.currentStyle
,差别在于element.currentStyle
返回的是元素当前应用的最终CSS属性值(包括外链CSS文件,页面中嵌入的<style>
属性等)。
(3)getPropertyValue方法可以获取CSS样式申明对象上的属性值(直接属性名称),例如:
window.getComputedStyle(element, null).getPropertyValue("float");
如果我们不使用getPropertyValue方法,直接使用键值访问,其实也是可以的。但是,比如这里的的float,如果使用键值访问,则不能直接使用getComputedStyle(element, null).float,而应该是cssFloat与styleFloat,自然需要浏览器判断了,比较折腾!
使用getPropertyValue方法不必可以驼峰书写形式(不支持驼峰写法),例如:style.getPropertyValue("border-top-left-radius");参见点击打开链接
(4)width重新设置为新的值以后浏览器会进行重排版,chrome<17和safari5.0用这种方式获取到margin-right等!