jQuery源码分析之width,height,innerWidth,innerHieght,outerWidth,outerHeight函数

来源:互联网 发布:亚马逊账号 阿里云 编辑:程序博客网 时间:2024/05/18 22:47

提前阅读:点击打开链接

(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为falsevar chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),//exta默认是defaultExtraextra = 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/764return 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 parseFloatjQuery.css( elem, type, extra ) :// Set width or height on the elementjQuery.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 prefixedif ( name in style ) {return name;}     //将name首字母大写,同时用origName保存没有首字母大写之前的名字// check for vendor prefixed namesvar 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 opacityvar 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那么设置为0fontWeight: "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 #12537ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;   if ( computed ) {             //如果获取到的属性值为空字符串同时该元素所在的文档不包括自身,那么调用jQuery.styleif ( 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对象,然后获取该对象的widthif ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {// Remember the original values//记住原始的width,minWidth,maxWidhwidth = style.width;minWidth = style.minWidth;maxWidth = style.maxWidth;                 //对minWidth,maxWidth,width赋值为新值,该值通过getComputedStyle方法获取到// Put in the new values to get a computed value outstyle.minWidth = style.maxWidth = style.width = ret;ret = computed.width;// Revert the changed valuesstyle.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 valuesleft = style.left;rs = elem.runtimeStyle;rsLeft = rs && rs.left;// Put in the new values to get a computed value outif ( rsLeft ) {rs.left = elem.currentStyle.left;}style.left = name === "fontSize" ? "1em" : ret;ret = style.pixelLeft + "px";// Revert the changed valuesstyle.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等!

0 0
原创粉丝点击