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 firefox不显示本地预览图片问题的解决方法
Nov 12 Javascript
jquery.qrcode在线生成二维码使用示例
Aug 21 Javascript
基于jquery实现的定时显示与隐藏div广告的实现代码
Aug 22 Javascript
JS记录用户登录次数实现代码
Jan 15 Javascript
详谈JavaScript内存泄漏
Nov 14 Javascript
Javascript实现可旋转的圆圈实例代码
Aug 04 Javascript
利用jQuery实现CheckBox全选/全不选/反选的简单代码
May 31 Javascript
Angular Module声明和获取重载实例代码
Sep 14 Javascript
原生JS实现图片左右轮播
Dec 30 Javascript
使用微信SDK自定义分享的方法
Jul 03 Javascript
vue实现导航标题栏随页面滚动渐隐渐显效果
Mar 12 Javascript
微信小程序实现聊天室功能
Jun 14 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
php pcntl_fork和pcntl_fork 的用法
2009/04/13 PHP
理解php原理的opcodes(操作码)
2010/10/26 PHP
JS setCapture 区域外事件捕捉
2010/03/18 Javascript
使用原生javascript创建通用表单验证——更锋利的使用dom对象
2011/09/13 Javascript
javascript中字符串的定义示例代码
2013/12/19 Javascript
基于JS2Image实现圣诞树代码
2015/12/24 Javascript
用JS实现图片轮播效果代码(一)
2016/06/26 Javascript
jquery+ajax实现省市区三级联动效果简单示例
2017/01/04 Javascript
a标签置灰不可点击的实现方法
2017/02/06 Javascript
Vue 2.5 Level E 发布了: 新功能特性一览
2017/10/24 Javascript
vue axios整合使用全攻略
2018/05/24 Javascript
使用vue2实现带地区编号和名称的省市县三级联动效果
2018/11/05 Javascript
微信小程序12行js代码自己写个滑块功能(推荐)
2020/07/15 Javascript
JavaScript 监听组合按键思路及代码实现
2020/07/28 Javascript
在vue中使用cookie记住用户上次选择的实例(本次例子中为下拉框)
2020/09/11 Javascript
使用python BeautifulSoup库抓取58手机维修信息
2013/11/21 Python
使用wxpython实现的一个简单图片浏览器实例
2014/07/10 Python
python爬虫框架talonspider简单介绍
2017/06/09 Python
利用python求相邻数的方法示例
2017/08/18 Python
python安装模块如何通过setup.py安装(超简单)
2018/05/05 Python
Python Requests库基本用法示例
2018/08/20 Python
python批量复制图片到另一个文件夹
2018/09/17 Python
Python队列、进程间通信、线程案例
2019/10/25 Python
python 解决print数组/矩阵无法完整输出的问题
2020/02/19 Python
详解Python3中的 input() 函数
2020/03/18 Python
使用Keras 实现查看model weights .h5 文件的内容
2020/06/09 Python
html5 Canvas画图教程(6)—canvas里画曲线之arcTo方法
2013/01/09 HTML / CSS
HTML5视频播放插件 video.js介绍
2018/09/29 HTML / CSS
英国高级百货公司:Harvey Nichols
2017/01/29 全球购物
Omio俄罗斯:一次搜索公共汽车、火车和飞机的机票
2018/11/17 全球购物
美国相机和电子产品零售商:Beach Camera
2020/11/26 全球购物
学期研究性学习个人的自我评价
2014/01/09 职场文书
《草原的早晨》教学反思
2014/04/08 职场文书
协商一致解除劳动合同协议书
2014/09/14 职场文书
2015年挂职干部工作总结
2015/05/14 职场文书
《辉夜大小姐想让我告白》第三季正式预告
2022/03/20 日漫