getBoundingClientRect的兼容函数分析
function getBoundingClientRect(element) {
if (typeof arguments.callee.offset != "number") {
var scrollTop = document.documentElement.scrollTop
var temp = document.createElement("div")
temp.style.cssText = "position:absolute;left:0;top:0"
document.body.appendChild(temp)
arguments.callee.offset = -temp.getBoundingClientRect().top - scrollTop;
document.body.removeChild(temp)
temp = null
}
var rect = element.getBoundingClientRect()
var offset = arguments.callee.offset
//offset在IE7中是-2 其他是0
return {
left: rect.left + offset,
right: rect.right + offset,
top: rect.top + offset,
bottom: rect.bottom + offset
}
}
- DOM元素通过原型链中的Element构造函数获得方法getBoundingClientRect()
- 而在IE7及更早的版本中位于左上角(0,0)处的元素的位置会返回(2,2)的坐标,所以才需要重新写一个函数。
在一些书里写是IE8及更早的版本,然而经测试是IE7及更早的版本才会返回(2,2)。
-
重点!!!这里的if语句非常漂亮
-
因为对于浏览器左上角的测试只需要一次即可!!!所以这里对arguments.callee进行赋值。
第一次调用函数时arguments.callee不存在offset属性,所以进入if中的语句块,对arguments.callee.offset进行赋值。
因为对arguments.callee赋值是直接对函数本身进行修改。(也就是说接下来每一次调用这个函数时,函数都将自带arguments.callee.offset)
如图,调用过一次之后再console.dir()的结果是
-
在调用前是这样的
-
我认为此函数应该如下更改更容易理解
function MygetBoundingClientRect(element) {
//判断是否已经运行过此函数,如果已运行过,则会在arguments.callee.offset保存浏览器的数据,也就不再进入if语句块
if (typeof arguments.callee.offset != "number") {
//计算滚动条外的长度(用于去除)
var scrollTop = document.documentElement.scrollTop
//创建一个dom元素用于测量左上角的坐标是(0,0)还是(2,2)
var temp = document.createElement("div")
//这一步非常重要,必须绝对定位定位在左上角,不然会加到文档的末尾测量出现巨大偏差。
temp.style.cssText = "position:absolute;left:0;top:0"
document.body.appendChild(temp)
//去除窗口外的距离,如果IE<=7则
arguments.callee.offset = -temp.getBoundingClientRect().top - scrollTop;
//移除元素
document.body.removeChild(temp)
//解除对DOM对象的引用,减少其引用数,确保正常回收其占用的内用
temp = null
}
//这里的getBoundingClientRect方法是继承于Element的原型方法的,而不是我们定义的函数,所以我区分了一下
var rect = element.getBoundingClientRect()
var offset = arguments.callee.offset
console.log(offset)
return {
left: rect.left + offset,
right: rect.right + offset,
top: rect.top + offset,
bottom: rect.bottom + offset
}
}