position是prototype中定义的一个对象,提供了操作dom中与位置相关的方法,要很好的理解元素在页面中的位置,可以参考这篇文章:relatively absolute
具体代码如下,按照代码说说,其中英文是作者的注释,中文红色的才是偶的说明或翻译英文的注释,采用顶式注释法(注释在要说明的代码的上面)说明
// set to true if needed, warning: firefox performance problems
// not neeeded for page scrolling, only if draggable contained in
// scrollable elements
//只有在使用拖动的时候元素包含在有滚动条的元素中才需要设置为true
includescrolloffsets: false,
// must be called before calling withinincludingscrolloffset, every time the
// page is scrolled
//当页面被scrolled后,使用withinincludingscrolloffset的时候需要先调用这个方法
prepare: function() {
//横向滚动条滚动的距离
this.deltax = window.pagexoffset
|| document.documentelement.scrollleft
|| document.body.scrollleft
|| 0;
//纵向滚动条滚动的距离
this.deltay = window.pageyoffset
|| document.documentelement.scrolltop
|| document.body.scrolltop
|| 0;
},
//元素由于滚动条偏移的总距离
realoffset: function(element) {
var valuet = 0, valuel = 0;
do {
valuet += element.scrolltop || 0;
valuel += element.scrollleft || 0;
element = element.parentnode;
} while (element);
return [valuel, valuet];
},
//元素在页面中由offsetparent累积的offset,当offsetparent都没有滚动条时,就是元素在页面中的位置
cumulativeoffset: function(element) {
var valuet = 0, valuel = 0;
do {
valuet += element.offsettop || 0;
valuel += element.offsetleft || 0;
element = element.offsetparent;
} while (element);
return [valuel, valuet];
},
//元素相对于containing block(nearest positioned ancestor)的位置,也就是相对于最近的一个position设置为relative或者absolute的祖先节点的位置,如果没有就是相对于body的位置,跟style.top,style.left一样?
positionedoffset: function(element) {
var valuet = 0, valuel = 0;
do {
valuet += element.offsettop || 0;
valuel += element.offsetleft || 0;
element = element.offsetparent;
if (element) {
if(element.tagname=='body') break;
var p = element.getstyle(element, 'position');
if (p == 'relative' || p == 'absolute') break;
}
} while (element);
return [valuel, valuet];
},
//offsetparent
offsetparent: function(element) {
if (element.offsetparent) return element.offsetparent;
if (element == document.body) return element;
while ((element = element.parentnode) && element != document.body)
if (element.getstyle(element, 'position') != 'static')
return element;
return document.body;
},
// caches x/y coordinate pair to use with overlap
//判断指定的位置是否在元素内
within: function(element, x, y) {
if (this.includescrolloffsets)
return this.withinincludingscrolloffsets(element, x, y);
this.xcomp = x;
this.ycomp = y;
this.offset = this.cumulativeoffset(element);
return (y >= this.offset[1] &&
y x >= this.offset[0] &&
x },
//跟within差不多,不过考虑到滚动条,也许是在元素上面,但不是直接在上面,因为滚动条也许已经使元素不可见了
withinincludingscrolloffsets: function(element, x, y) {
var offsetcache = this.realoffset(element);
this.xcomp = x + offsetcache[0] - this.deltax;
this.ycomp = y + offsetcache[1] - this.deltay;
this.offset = this.cumulativeoffset(element);
return (this.ycomp >= this.offset[1] &&
this.ycomp this.xcomp >= this.offset[0] &&
this.xcomp },
// within must be called directly before
//在调用这个方法前,必须先调用within,返回在with指定的位置在水平或者垂直方向上占用的百分比
overlap: function(mode, element) {
if (!mode) return 0;
if (mode == 'vertical')
return ((this.offset[1] + element.offsetheight) - this.ycomp) /
element.offsetheight;
if (mode == 'horizontal')
return ((this.offset[0] + element.offsetwidth) - this.xcomp) /
element.offsetwidth;
},
//返回元素相对页面的真实位置
page: function(forelement) {
var valuet = 0, valuel = 0;
var element = forelement;
do {
valuet += element.offsettop || 0;
valuel += element.offsetleft || 0;
// safari fix
if (element.offsetparent==document.body)
if (element.getstyle(element,'position')=='absolute') break;
} while (element = element.offsetparent);
element = forelement;
do {
if (!window.opera || element.tagname=='body') {
valuet -= element.scrolltop || 0;
valuel -= element.scrollleft || 0;
}
} while (element = element.parentnode);
return [valuel, valuet];
},
//设置target为source的位置,大小
clone: function(source, target) {
var options = object.extend({
setleft: true,
settop: true,
setwidth: true,
setheight: true,
offsettop: 0,
offsetleft: 0
}, arguments[2] || {})
// find page position of source
source = $(source);
var p = position.page(source);
// find coordinate system to use
target = $(target);
var delta = [0, 0];
var parent = null;
// delta [0,0] will do fine with position: fixed elements,
// position:absolute needs offsetparent deltas
if (element.getstyle(target,'position') == 'absolute') {
parent = position.offsetparent(target);
delta = position.page(parent);
}
// correct by body offsets (fixes safari)
if (parent == document.body) {
delta[0] -= document.body.offsetleft;
delta[1] -= document.body.offsettop;
}
// set position
if(options.setleft) target.style.left = (p[0] - delta[0] + options.offsetleft) + 'px';
if(options.settop) target.style.top = (p[1] - delta[1] + options.offsettop) + 'px';
if(options.setwidth) target.style.width = source.offsetwidth + 'px';
if(options.setheight) target.style.height = source.offsetheight + 'px';
},
//将element的position设置为absolute的模式
absolutize: function(element) {
element = $(element);
if (element.style.position == 'absolute') return;
position.prepare();
var offsets = position.positionedoffset(element);
var top = offsets[1];
var left = offsets[0];
var width = element.clientwidth;
var height = element.clientheight;
element._originalleft = left - parsefloat(element.style.left || 0);
element._originaltop = top - parsefloat(element.style.top || 0);
element._originalwidth = element.style.width;
element._originalheight = element.style.height;
element.style.position = 'absolute';
element.style.top = top + 'px';;
element.style.left = left + 'px';;
element.style.width = width + 'px';;
element.style.height = height + 'px';;
},
//将element的position设置为absolute的模式
relativize: function(element) {
element = $(element);
if (element.style.position == 'relative') return;
position.prepare();
element.style.position = 'relative';
var top = parsefloat(element.style.top || 0) - (element._originaltop || 0);
var left = parsefloat(element.style.left || 0) - (element._originalleft || 0);
element.style.top = top + 'px';
element.style.left = left + 'px';
element.style.height = element._originalheight;
element.style.width = element._originalwidth;
}
}
// safari returns margins on body which is incorrect if the child is absolutely
// positioned. for performance reasons, redefine position.cumulativeoffset for
// khtml/webkit only.
if (/konqueror|safari|khtml/.test(navigator.useragent)) {
position.cumulativeoffset = function(element) {
var valuet = 0, valuel = 0;
do {
valuet += element.offsettop || 0;
valuel += element.offsetleft || 0;
if (element.offsetparent == document.body)
if (element.getstyle(element, 'position') == 'absolute') break;
element = element.offsetparent;
} while (element);
return [valuel, valuet];
}
}
终于把prototype的所有部分都写完了,哈哈,越来越佩服自己的耐力了
下一步决定写写scriptaculous这个超级流行的效果库