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


Posted in Javascript onJanuary 10, 2007

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这个超级流行的效果库

Javascript 相关文章推荐
Javascript 键盘keyCode键码值表
Dec 24 Javascript
jQuery基础知识filter()和find()实例说明
Jul 06 Javascript
myEvent.js javascript跨浏览器事件框架
Oct 24 Javascript
JavaScript学习笔记(二) js对象
Oct 25 Javascript
详解 javascript中offsetleft属性的用法
Nov 11 Javascript
在vue.js中抽出公共代码的方法示例
Jun 08 Javascript
深入理解Angular中的依赖注入
Jun 26 Javascript
Vue指令v-for遍历输出JavaScript数组及json对象的常见方式小结
Feb 11 Javascript
利用d3.js实现蜂巢图表带动画效果
Sep 03 Javascript
vue项目中使用多选框的实例代码
Jul 22 Javascript
vue中echarts引入中国地图的案例
Jul 28 Javascript
js实现扫雷源代码
Nov 27 Javascript
Prototype使用指南之form.js
Jan 10 #Javascript
Prototype使用指南之selector.js
Jan 10 #Javascript
Prototype使用指南之dom.js
Jan 10 #Javascript
Prototype使用指南之ajax
Jan 10 #Javascript
Prototype使用指南之range.js
Jan 10 #Javascript
Prototype使用指南之hash.js
Jan 10 #Javascript
Prototype使用指南之array.js
Jan 10 #Javascript
You might like
PHILIPS AE3805收音机的分析打磨
2021/03/02 无线电
详细介绍:Apache+PHP+MySQL配置攻略
2006/09/05 PHP
php使用unset()删除数组中某个单元(键)的方法
2015/02/17 PHP
php实现统计网站在线人数的方法
2015/05/12 PHP
浅谈PHP接收POST数据方式
2015/06/05 PHP
Apache无法自动跳转却显示目录的解决方法
2020/11/30 PHP
php版微信公众号接口实现发红包的方法
2016/10/14 PHP
CI框架中类的自动加载问题分析
2016/11/21 PHP
thinkPHP5.0框架应用请求生命周期分析
2017/03/25 PHP
微信公众号开发之获取位置信息php代码
2018/06/13 PHP
解放web程序员的输入验证
2006/10/06 Javascript
完整显示当前日期和时间的JS代码
2007/09/17 Javascript
JavaScript Event学习第八章 事件的顺序
2010/02/07 Javascript
javascript工具库代码
2012/03/29 Javascript
Javascript图像处理—为矩阵添加常用方法
2012/12/27 Javascript
js控制浏览器全屏示例代码
2014/02/20 Javascript
node.js中的fs.lchmod方法使用说明
2014/12/16 Javascript
javascript实现淘宝幻灯片广告展示效果
2015/04/27 Javascript
详解VUE里子组件如何获取父组件动态变化的值
2018/12/26 Javascript
redux.js详解及基本使用
2019/05/24 Javascript
Vue extend的基本用法(实例详解)
2019/12/09 Javascript
Django用户认证系统 Web请求中的认证解析
2019/08/02 Python
python文件处理fileinput使用方法详解
2020/01/02 Python
css 元素选择器的简单实例
2016/05/23 HTML / CSS
html5 canvas实现跟随鼠标旋转的箭头
2016/03/11 HTML / CSS
使用phonegap检测网络状态的方法
2017/03/30 HTML / CSS
地球上最先进的胡子和头发修剪器:Bevel
2018/01/23 全球购物
绩效专员岗位职责
2013/12/02 职场文书
领导的自我鉴定
2013/12/28 职场文书
演讲稿怎么写
2014/01/07 职场文书
《雨点儿》教学反思
2014/04/14 职场文书
小学班主任评语大全
2014/04/23 职场文书
销售人才自我评价范文
2014/09/27 职场文书
基层工作经历证明
2015/06/19 职场文书
七个Python必备的GUI库
2021/04/27 Python
python 详解turtle画爱心代码
2022/02/15 Python