[转帖]Mootools源码分析-19 -- Element-6
原帖地址:http://space.flash8.net/space/?uid-18713-action-viewspace-itemid-403472
原作者:我佛山人
/*
本部分主要为Element提供取尺寸相关的兼容方法
*/
(function() {
Element.implement({
//使可视范围滚动到指定坐标
scrollTo: function(x, y) {
//如果当前是body,让页面的滚动条滚动
if (isBody(this)) {
this.getWindow().scrollTo(x, y);
} else {
this.scrollLeft = x;
this.scrollTop = y;
}
return this;
},
//获取对象的布局尺寸
getSize: function() {
if (isBody(this)) return this.getWindow().getSize();
return {x: this.offsetWidth, y: this.offsetHeight};
},
//获取对象的滚动尺寸
getScrollSize: function() {
if (isBody(this)) return this.getWindow().getScrollSize();
return {x: this.scrollWidth, y: this.scrollHeight};
},
//获取滚动位置
getScroll: function() {
if (isBody(this)) return this.getWindow().getScroll();
return {x: this.scrollLeft, y: this.scrollTop};
},
//获取相对文档的滚动位置
getScrolls: function() {
var element = this, position = {x: 0, y: 0};
while (element && !isBody(element)) {
position.x += element.scrollLeft;
position.y += element.scrollTop;
element = element.parentNode;
}
return position;
},
//获取总的偏移量
getOffsets: function() {
var element = this, position = {x: 0, y: 0};
//如果是根节点,坐标为原点
if (isBody(this)) return position;
while (element && !isBody(element)) {
position.x += element.offsetLeft;
position.y += element.offsetTop;
if (Browser.Engine.gecko) {
//firefox的处理,如果不使用盒模型,需要加上左和上边框的宽度
if (!borderBox(element)) {
position.x += leftBorder(element);
position.y += topBorder(element);
}
var parent = element.parentNode;
if (parent && styleString(parent, 'overflow') != 'visible') {
position.x += leftBorder(parent);
position.y += topBorder(parent);
}
} else if (element != this && (Browser.Engine.trident || Browser.Engine.webkit)) {
//IE和Safari也需要加上边框,看来这里只有Opera比较符合标准,Safari次之
position.x += leftBorder(element);
position.y += topBorder(element);
}
element = element.offsetParent;
if (Browser.Engine.trident) {
//忽略IE下没有hasLayout的element
while (element && !element.currentStyle.hasLayout) element = element.offsetParent;
}
}
//firefox下不使用盒模型解决时需要再减去当前的上左边框宽度
if (Browser.Engine.gecko && !borderBox(this)) {
position.x -= leftBorder(this);
position.y -= topBorder(this);
}
return position;
},
//获取坐标值,如果提供relative参数,则返回相对于ralative的坐标值
getPosition: function(relative) {
//根节点坐标为原点
if (isBody(this)) return {x: 0, y: 0};
//取偏移值和滚动条位置
var ōffset = this.getOffsets(), scroll = this.getScrolls();
//得到坐标值
var position = {x: offset.x - scroll.x, y: offset.y - scroll.y};
//求相对坐标值
var relativePosition = (relative && (relative = $(relative))) ? relative.getPosition() : {x: 0, y: 0};
return {x: position.x - relativePosition.x, y: position.y - relativePosition.y};
},
//获取坐标和尺寸
getCoordinates: function(element) {
//根节点处理
if (isBody(this)) return this.getWindow().getCoordinates();
//分别获取坐标与尺寸
var position = this.getPosition(element), size = this.getSize();
//新的表示形式
var obj = {left: position.x, top: position.y, width: size.x, height: size.y};
//右下坐标的计算
obj.right = obj.left + obj.width;
obj.bottom = obj.top + obj.height;
return obj;
},
//计算运行时坐标,会受margin-left和margin-top影响
computePosition: function(obj) {
return {left: obj.x - styleNumber(this, 'margin-left'), top: obj.y - styleNumber(this, 'margin-top')};
},
//定位
position: function(obj) {
return this.setStyles(this.computePosition(obj));
}
});
//对Document和Window实现Element的同名方法,因为具体实现有别于一般Element
Native.implement([Document, Window], {
//获取尺寸
getSize: function() {
var win = this.getWindow();
//Opera和Safari的处理
if (Browser.Engine.presto || Browser.Engine.webkit) return {x: win.innerWidth, y: win.innerHeight};
var doc = getCompatElement(this);
return {x: doc.clientWidth, y: doc.clientHeight};
},
//获取滚动坐标
getScroll: function() {
var win = this.getWindow();
var doc = getCompatElement(this);
return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop};
},
//获取滚动尺寸
getScrollSize: function() {
var doc = getCompatElement(this);
var min = this.getSize();
return {x: Math.max(doc.scrollWidth, min.x), y: Math.max(doc.scrollHeight, min.y)};
},
//定位
getPosition: function() {
return {x: 0, y: 0};
},
//获取尺寸和坐标
getCoordinates: function() {
var size = this.getSize();
return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x};
}
});
// 私有方法
//获取运行时的样式属性
var styleString = Element.getComputedStyle;
//获取运行时的样式属性的数字值
function styleNumber(element, style) {
return styleString(element, style).toInt() || 0;
};
//获取盒尺寸的mozilla家庭私有属性
function borderBox(element) {
return styleString(element, '-moz-box-sizing') == 'border-box';
};
//获取上边框的宽度
function topBorder(element) {
return styleNumber(element, 'border-top-width');
};
//获取左边框宽度
function leftBorder(element) {
return styleNumber(element, 'border-left-width');
};
//测试element是否body或html节点
function isBody(element) {
return (/^(?:body|html)$/i).test(element.tagName);
};
//根据当前文档是否使用标准模式而返回页面根节点,html或body
function getCompatElement(element) {
var doc = element.getDocument();
return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
};
})();
//别名
Native.implement([Window, Document, Element], {
//获取高度,依赖getSize方法
getHeight: function() {
return this.getSize().y;
},
//获取宽度,依赖getSize方法
getWidth: function() {
return this.getSize().x;
},
//获取y轴滚动坐标,依赖getScroll方法
getScrollTop: function() {
return this.getScroll().y;
},
//获取x轴滚动坐标,依赖getScroll方法
getScrollLeft: function(){
return this.getScroll().x;
},
//获取滚动高度,依赖getScrollSize方法
getScrollHeight: function(){
return this.getScrollSize().y;
},
//获取滚动宽度,依赖getScrollSize方法
getScrollWidth: function(){
return this.getScrollSize().x;
},
//获取y坐标,依赖getPosition方法
getTop: function(){
return this.getPosition().y;
},
//获取x坐标,依赖getPosition方法
getLeft: function(){
return this.getPosition().x;
}
});
本部分主要为Element提供取尺寸相关的兼容方法
*/
(function() {
Element.implement({
//使可视范围滚动到指定坐标
scrollTo: function(x, y) {
//如果当前是body,让页面的滚动条滚动
if (isBody(this)) {
this.getWindow().scrollTo(x, y);
} else {
this.scrollLeft = x;
this.scrollTop = y;
}
return this;
},
//获取对象的布局尺寸
getSize: function() {
if (isBody(this)) return this.getWindow().getSize();
return {x: this.offsetWidth, y: this.offsetHeight};
},
//获取对象的滚动尺寸
getScrollSize: function() {
if (isBody(this)) return this.getWindow().getScrollSize();
return {x: this.scrollWidth, y: this.scrollHeight};
},
//获取滚动位置
getScroll: function() {
if (isBody(this)) return this.getWindow().getScroll();
return {x: this.scrollLeft, y: this.scrollTop};
},
//获取相对文档的滚动位置
getScrolls: function() {
var element = this, position = {x: 0, y: 0};
while (element && !isBody(element)) {
position.x += element.scrollLeft;
position.y += element.scrollTop;
element = element.parentNode;
}
return position;
},
//获取总的偏移量
getOffsets: function() {
var element = this, position = {x: 0, y: 0};
//如果是根节点,坐标为原点
if (isBody(this)) return position;
while (element && !isBody(element)) {
position.x += element.offsetLeft;
position.y += element.offsetTop;
if (Browser.Engine.gecko) {
//firefox的处理,如果不使用盒模型,需要加上左和上边框的宽度
if (!borderBox(element)) {
position.x += leftBorder(element);
position.y += topBorder(element);
}
var parent = element.parentNode;
if (parent && styleString(parent, 'overflow') != 'visible') {
position.x += leftBorder(parent);
position.y += topBorder(parent);
}
} else if (element != this && (Browser.Engine.trident || Browser.Engine.webkit)) {
//IE和Safari也需要加上边框,看来这里只有Opera比较符合标准,Safari次之
position.x += leftBorder(element);
position.y += topBorder(element);
}
element = element.offsetParent;
if (Browser.Engine.trident) {
//忽略IE下没有hasLayout的element
while (element && !element.currentStyle.hasLayout) element = element.offsetParent;
}
}
//firefox下不使用盒模型解决时需要再减去当前的上左边框宽度
if (Browser.Engine.gecko && !borderBox(this)) {
position.x -= leftBorder(this);
position.y -= topBorder(this);
}
return position;
},
//获取坐标值,如果提供relative参数,则返回相对于ralative的坐标值
getPosition: function(relative) {
//根节点坐标为原点
if (isBody(this)) return {x: 0, y: 0};
//取偏移值和滚动条位置
var ōffset = this.getOffsets(), scroll = this.getScrolls();
//得到坐标值
var position = {x: offset.x - scroll.x, y: offset.y - scroll.y};
//求相对坐标值
var relativePosition = (relative && (relative = $(relative))) ? relative.getPosition() : {x: 0, y: 0};
return {x: position.x - relativePosition.x, y: position.y - relativePosition.y};
},
//获取坐标和尺寸
getCoordinates: function(element) {
//根节点处理
if (isBody(this)) return this.getWindow().getCoordinates();
//分别获取坐标与尺寸
var position = this.getPosition(element), size = this.getSize();
//新的表示形式
var obj = {left: position.x, top: position.y, width: size.x, height: size.y};
//右下坐标的计算
obj.right = obj.left + obj.width;
obj.bottom = obj.top + obj.height;
return obj;
},
//计算运行时坐标,会受margin-left和margin-top影响
computePosition: function(obj) {
return {left: obj.x - styleNumber(this, 'margin-left'), top: obj.y - styleNumber(this, 'margin-top')};
},
//定位
position: function(obj) {
return this.setStyles(this.computePosition(obj));
}
});
//对Document和Window实现Element的同名方法,因为具体实现有别于一般Element
Native.implement([Document, Window], {
//获取尺寸
getSize: function() {
var win = this.getWindow();
//Opera和Safari的处理
if (Browser.Engine.presto || Browser.Engine.webkit) return {x: win.innerWidth, y: win.innerHeight};
var doc = getCompatElement(this);
return {x: doc.clientWidth, y: doc.clientHeight};
},
//获取滚动坐标
getScroll: function() {
var win = this.getWindow();
var doc = getCompatElement(this);
return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop};
},
//获取滚动尺寸
getScrollSize: function() {
var doc = getCompatElement(this);
var min = this.getSize();
return {x: Math.max(doc.scrollWidth, min.x), y: Math.max(doc.scrollHeight, min.y)};
},
//定位
getPosition: function() {
return {x: 0, y: 0};
},
//获取尺寸和坐标
getCoordinates: function() {
var size = this.getSize();
return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x};
}
});
// 私有方法
//获取运行时的样式属性
var styleString = Element.getComputedStyle;
//获取运行时的样式属性的数字值
function styleNumber(element, style) {
return styleString(element, style).toInt() || 0;
};
//获取盒尺寸的mozilla家庭私有属性
function borderBox(element) {
return styleString(element, '-moz-box-sizing') == 'border-box';
};
//获取上边框的宽度
function topBorder(element) {
return styleNumber(element, 'border-top-width');
};
//获取左边框宽度
function leftBorder(element) {
return styleNumber(element, 'border-left-width');
};
//测试element是否body或html节点
function isBody(element) {
return (/^(?:body|html)$/i).test(element.tagName);
};
//根据当前文档是否使用标准模式而返回页面根节点,html或body
function getCompatElement(element) {
var doc = element.getDocument();
return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
};
})();
//别名
Native.implement([Window, Document, Element], {
//获取高度,依赖getSize方法
getHeight: function() {
return this.getSize().y;
},
//获取宽度,依赖getSize方法
getWidth: function() {
return this.getSize().x;
},
//获取y轴滚动坐标,依赖getScroll方法
getScrollTop: function() {
return this.getScroll().y;
},
//获取x轴滚动坐标,依赖getScroll方法
getScrollLeft: function(){
return this.getScroll().x;
},
//获取滚动高度,依赖getScrollSize方法
getScrollHeight: function(){
return this.getScrollSize().y;
},
//获取滚动宽度,依赖getScrollSize方法
getScrollWidth: function(){
return this.getScrollSize().x;
},
//获取y坐标,依赖getPosition方法
getTop: function(){
return this.getPosition().y;
},
//获取x坐标,依赖getPosition方法
getLeft: function(){
return this.getPosition().x;
}
});