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 相关文章推荐
Lazy Load 延迟加载图片的 jQuery 插件
Feb 06 Javascript
基于jquery的图片轮播 tab切换组件
Jul 19 Javascript
javascript获取作用在元素上面的样式属性代码
Sep 20 Javascript
nodeType属性返回被选节点的节点类型介绍
Nov 22 Javascript
使用Raygun对Node.js应用进行错误处理的方法
Jun 23 Javascript
JavaScript中Function函数与Object对象的关系
Dec 17 Javascript
纯javascript版日历控件
Nov 24 Javascript
Bootstrap基本插件学习笔记之Alert警告框(20)
Dec 08 Javascript
javascript标准库(js的标准内置对象)总结
May 26 Javascript
详解vue中axios请求的封装
Apr 08 Javascript
简单了解Vue + ElementUI后台管理模板
Apr 07 Javascript
用vue设计一个日历表
Dec 03 Vue.js
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
解析centos中Apache、php、mysql 默认安装路径
2013/06/25 PHP
thinkPHP5.0框架验证码调用及点击图片刷新简单实现方法
2018/09/07 PHP
6款经典实用的jQuery小插件及源码(对话框/提示工具等等)
2013/02/04 Javascript
javascript实现分栏显示小技巧附图
2014/10/13 Javascript
JavaScript基于setTimeout实现计数的方法
2015/05/08 Javascript
用JavaScript显示浏览器客户端信息的超相近教程
2015/06/18 Javascript
jquery实现的代替传统checkbox样式插件
2015/06/19 Javascript
JavaScript实现非常简单实用的下拉菜单效果
2015/08/27 Javascript
js实现简单折叠、展开菜单的方法
2015/08/28 Javascript
谈一谈javascript中继承的多种方式
2016/02/19 Javascript
jQuery插件ImageDrawer.js实现动态绘制图片动画(附源码下载)
2016/02/25 Javascript
JS中如何比较两个Json对象是否相等实例代码
2016/07/13 Javascript
AngularJS实现标签页的两种方式
2016/09/05 Javascript
JS键盘版计算器的制作方法
2016/12/03 Javascript
JS实现的四级密码强度检测功能示例
2017/05/11 Javascript
微信小程序本地缓存数据增删改查实例详解
2017/05/24 Javascript
Angular搜索 过滤 批量删除 添加 表单验证功能集锦(实例代码)
2017/10/25 Javascript
JavaScript实现alert弹框效果
2020/11/19 Javascript
vue element实现表格合并行数据
2020/11/30 Vue.js
编写同时兼容Python2.x与Python3.x版本的代码的几个示例
2015/03/30 Python
在Python的Tornado框架中实现简单的在线代理的教程
2015/05/02 Python
Python中在脚本中引用其他文件函数的实现方法
2016/06/23 Python
Python实现定时任务
2017/02/08 Python
简单学习Python多进程Multiprocessing
2017/08/29 Python
详解Python 字符串相似性的几种度量方法
2019/08/29 Python
Python实现打包成库供别的模块调用
2020/07/13 Python
5分钟弄清楚html5的drag and drop(小结)
2019/04/10 HTML / CSS
墨西哥网上超市:Superama
2018/07/10 全球购物
Petmate品牌官方网站:宠物用品
2018/11/25 全球购物
程序员岗位职责
2013/11/11 职场文书
建筑专业自荐信范文
2014/01/05 职场文书
幸福家庭标语
2014/06/27 职场文书
2015年体育教学工作总结
2015/05/20 职场文书
司法廉洁教育心得体会
2016/01/20 职场文书
python 字典和列表嵌套用法详解
2021/06/29 Python
基于Redis zSet实现滑动窗口对短信进行防刷限流的问题
2022/02/12 Redis