详解原生js实现offset方法


Posted in Javascript onJune 15, 2017

在为 jTool 提供 offset (获取当前节点位置)方法时, 先后使用了两种方式进行实现, 现整理出来以作记录。

前后共使用了两种方式实现了该方法, 这里将这两种方法分别列出。

通过递归实现

function offset(element) {
  var offest = {
    top: 0,
    left: 0
  };

  var _position;

  getOffset(element, true);

  return offest;

  // 递归获取 offset, 可以考虑使用 getBoundingClientRect
  function getOffset(node, init) {
    // 非Element 终止递归
    if (node.nodeType !== 1) {
      return;
    }
    _position = window.getComputedStyle(node)['position'];

    // position=static: 继续递归父节点
    if (typeof(init) === 'undefined' && _position === 'static') {
      getOffset(node.parentNode);
      return;
    }
    offest.top = node.offsetTop + offest.top - node.scrollTop;
    offest.left = node.offsetLeft + offest.left - node.scrollLeft;

    // position = fixed: 获取值后退出递归
    if (_position === 'fixed') {
      return;
    }

    getOffset(node.parentNode);
  }
}
// 执行offset
var s_kw_wrap = document.querySelector('#s_kw_wrap');
offset(s_kw_wrap); // => Object {top: 181, left: 400}

通过ClientRect实现

function offset2(node) {
  var offest = {
    top: 0,
    left: 0
  };
  // 当前为IE11以下, 直接返回{top: 0, left: 0}
  if (!node.getClientRects().length) {
    return offest;
  }
  // 当前DOM节点的 display === 'node' 时, 直接返回{top: 0, left: 0}
  if (window.getComputedStyle(node)['display'] === 'none') {
    return offest;
  }
  // Element.getBoundingClientRect()方法返回元素的大小及其相对于视口的位置。
  // 返回值包含了一组用于描述边框的只读属性——left、top、right和bottom,单位为像素。除了 width 和 height 外的属性都是相对于视口的左上角位置而言的。
  // 返回如{top: 8, right: 1432, bottom: 548, left: 8, width: 1424…}
  offest = node.getBoundingClientRect();
  var docElement = node.ownerDocument.documentElement;
  return {
    top: offest.top + window.pageYOffset - docElement.clientTop,
    left: offest.left + window.pageXOffset - docElement.clientLeft
  };
}
// 执行offset
var s_kw_wrap = document.querySelector('#s_kw_wrap');
offset2(s_kw_wrap); // => Object {top: 181.296875, left: 399.5}

offset2() 函数中使用到了 .getClientRects() 与 .getBoundingClientRect() 方法,IE11 以下浏览器并不支持; 所以该种实现, 只适于现代浏览器。

.getClientRects()

返回值是 ClientRect 对象集合(与该元素相关的CSS边框),每个 ClientRect 对象包含一组描述该边框的只读属性——left、top、right 和 bottom,单位为像素,这些属性值是相对于视口的top-left的。

并包含 length 属性, IE11以下可以通过是否包含 length 来验证当前是否为IE11以上版现。

.getBoundingClientRect()

返回值包含了一组用于描述边框的只读属性——left、top、right 和 bottom,单位为像素。除了 width 和 height 外的属性都是相对于视口的左上角位置而言的。

.getBoundingClientRect() 与 .getClientRects()的关系

  1. 这两个方法的区别与当前的 display 相关, 当 display=inline 时, .getClientRects() 返回当前节点内每一行文本的 ClientRect 对象数组, 此时数组长度等于文本行数。
  2. 当 display != inline 时, .getClientRects() 返回当前节点的 ClientRect 对象数组,此时数组长度为1.
  3. .getBoundingClientRect() 总是返回当前节点的 ClientRect 对象, 注意这里是 ClientRect 对象而不是对象数组。

提示

以上测试, 可以通过在百度首页执行进行测试, document.querySelect('#s_kw_wrap') 所获取到的节点为百度首页输入框

希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
使用Javascript和DOM Interfaces来处理HTML
Oct 09 Javascript
javascript之水平横向滚动歌词同步的应用
May 07 Javascript
jQuery编写widget的一些技巧分享
Oct 28 Javascript
JSON 数据格式介绍
Jan 13 Javascript
javascript获取网页中指定节点的父节点、子节点的方法小结
Apr 24 Javascript
node.js文件上传处理示例
Oct 27 Javascript
JavaScript日期对象(Date)基本用法示例
Jan 18 Javascript
Angular.JS中的this指向详解
May 17 Javascript
jquery easyui如何实现格式化列
Jul 30 jQuery
vue.js中$set与数组更新方法
Mar 08 Javascript
vue移动端的左右滑动事件详解
Jun 17 Javascript
el-form 多层级表单的实现示例
Sep 10 Javascript
微信小程序 监听手势滑动切换页面实例详解
Jun 15 #Javascript
微信小程序canvas写字板效果及实例
Jun 15 #Javascript
AngularJs实现聊天列表实时刷新功能
Jun 15 #Javascript
bootstrap daterangepicker双日历时间段选择控件详解
Jun 15 #Javascript
详解react-router如何实现按需加载
Jun 15 #Javascript
jQuery实现 RadioButton做必选校验功能
Jun 15 #jQuery
bootstrap daterangepicker汉化以及扩展功能
Jun 15 #Javascript
You might like
详谈PHP编码转换问题
2015/07/28 PHP
php对xml文件的增删改查操作实现方法分析
2017/05/19 PHP
PHP那些琐碎的知识点(整理)
2017/05/20 PHP
JSON序列化与解析原生JS方法且IE6和chrome测试通过
2013/09/05 Javascript
js获取某元素的class里面的css属性值代码
2014/01/16 Javascript
教你如何自定义百度分享插件以及bshare分享插件的分享按钮
2014/06/20 Javascript
jquery和js实现对div的隐藏和显示方法
2014/09/26 Javascript
BOOTSTRAP时间控件显示在模态框下面的bug修复
2015/02/05 Javascript
JS实现简单易用的手机端浮动窗口显示效果
2016/09/07 Javascript
JavaScript数组迭代方法
2017/03/03 Javascript
JS操作xml对象转换为Json对象示例
2017/03/25 Javascript
JS基于正则实现数字千分位用逗号分隔的方法
2017/06/16 Javascript
实例解析ES6 Proxy使用场景介绍
2018/01/08 Javascript
VUE UPLOAD 通过ACTION返回上传结果操作
2020/09/07 Javascript
js实现网页随机验证码
2020/10/19 Javascript
[55:32]2018DOTA2亚洲邀请赛 4.4 淘汰赛 EG vs LGD 第二场
2018/04/05 DOTA
Python中的FTP通信模块ftplib的用法整理
2016/07/08 Python
Python中模块与包有相同名字的处理方法
2017/05/05 Python
python爬取微信公众号文章的方法
2019/02/26 Python
简单了解python变量的作用域
2019/07/30 Python
python3 assert 断言的使用详解 (区别于python2)
2019/11/27 Python
python中round函数如何使用
2020/06/19 Python
如何在Win10系统使用Python3连接Hive
2020/10/15 Python
CSS3解析抖音LOGO制作的方法步骤
2019/04/11 HTML / CSS
AmazeUI 输入框组的示例代码
2020/08/14 HTML / CSS
remote接口和home接口主要作用
2013/05/15 面试题
Java servlet面试题
2012/03/04 面试题
生日礼品店创业计划书范文
2014/03/21 职场文书
《和田的维吾尔》教学反思
2014/04/14 职场文书
禁毒宣传标语
2014/06/19 职场文书
党支部创先争优承诺书
2014/08/30 职场文书
订货会主持词
2015/07/01 职场文书
教师学习心得体会范文
2016/01/21 职场文书
公证书
2019/04/17 职场文书
餐厅营销的秘密:为什么老顾客会流水?
2019/08/08 职场文书
Python使用OpenCV实现虚拟缩放效果
2022/02/28 Python