提前阅读:点击打开链接
(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等!