Prototype1.5 rc2版指南最后一篇之Position

  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 <  this.offset[1] + element.offsetHeight &&

  x >= this.offset[0] &&

  x <  this.offset[0] + element.offsetWidth);

  },

  //跟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.offset[1] + element.offsetHeight &&

  this.xcomp >= this.offset[0] &&

  this.xcomp <  this.offset[0] + element.offsetWidth);

  },

    // 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的所有部分都写完了哈哈,越来越佩服自己的耐力了

Prototype1.5 rc2版指南最后一篇之Position

  下一步决定写写Scriptaculous这个超级流行的效果库