在进入源码分析前,我们先来点基础知识。下面这张图画的是元素的盒式模型,这个没有兼容性问题,有问题的是元素的宽高怎么算。以宽度为例,ff中 元素宽度=content宽度,而在ie中 元素宽度=content宽度+border宽度+padding宽度。IE8中加入了box-sizzing,该css属性有两个值:border-box、content-box分别对应ie和ff中元素宽度的工作方式。
偏移量:offsetLeft、offsetTop、offsetWidth、offsetHeight
offsetLeft:包含元素的左内边框到元素的左外边框之间的像素距离。
offsetTop:包含元素的上内边框到元素的上外边框之间的相续距离。
offsetWidth:包括元素的内容区宽度、左右内边距宽度、左右边框宽度、垂直方向滚动条的宽度之和。
offsetHeight:包括元素内容区高度、左右内边距高度、左右边框高度、水平方向滚动条的高度之和。
包含元素的引用在offsetParent属性中,offsetParent属性不一定与parentNode属性相同,比如<td>的offsetParent是<table>而不是<tr>.
客户区大小:clientWidth、clientHeight
clientWidth:元素的内容区宽度+内边距宽度
clientHeight:元素的内容区高度+内边距高度
滚动大小:scrollTop、scrollLeft、scrollWidth、scrollHeight。滚动大小指的是包含滚动内容的元素大小。
scrollTop:被隐藏在内容区域上方的像素数。
scrollLeft:被隐藏在内容区域左侧的像素数。
通过设置以上两个属性可以改变元素的滚动位置。
scrollWidth:在没有滚动条情况下,元素的内容的宽度。
scrollHeight:在没有滚动条情况下,元素内容的高度。
以上基础知识,对我们分析dom-geometry模块的代码会有不少帮助。下面我们进入源码学习阶段。
dom-geometry模块封装了许多跟盒式模型相关的函数,主要涉及:content、padding、border、margin四方面。在前面的几篇文章中我们多次提到,前端js库中对dom操作的封装最终都是要用到DOM原生的API。在此模块中,最常用的原生方法就是elemet.ownerDocument.defaultView.getComputedStyle和element.getBoundingClientRect。尽管这两个方法都存在着兼容性问题,但我们都有适当的方法来解决。
getComputedStyle方法已经在dom-style模块中介绍过(ie中使用element.currentStyle其他浏览器利用原生的getComputedStyle,在webkit中对于不在正常文档流中的元素先改变display),这里简单看一下:
1 if(has("webkit")){ 2 getComputedStyle = function(/*DomNode*/ node){ 3 var s; 4 if(node.nodeType == 1){ 5 var dv = node.ownerDocument.defaultView; 6 s = dv.getComputedStyle(node, null); 7 if(!s && node.style){ 8 node.style.display = ""; 9 s = dv.getComputedStyle(node, null); 10 } 11 } 12 return s || {}; 13 }; 14 }else if(has("ie") && (has("ie") < 9 || has("quirks"))){ 15 getComputedStyle = function(node){ 16 // IE (as of 7) doesn't expose Element like sane browsers 17 // currentStyle can be null on IE8! 18 return node.nodeType == 1 /* ELEMENT_NODE*/ && node.currentStyle ? node.currentStyle : {}; 19 }; 20 }else{ 21 getComputedStyle = function(node){ 22 return node.nodeType == 1 /* ELEMENT_NODE*/ ? 23 node.ownerDocument.defaultView.getComputedStyle(node, null) : {}; 24 }; 25 } 26 style.getComputedStyle = getComputedStyle;