详解原生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 相关文章推荐
JS滚轮事件onmousewheel使用介绍
Nov 01 Javascript
js获得当前时区夏令时发生和终止的时间代码
Feb 23 Javascript
Javascript中对象继承的实现小例
May 12 Javascript
Node.js中使用事件发射器模式实现事件绑定详解
Aug 15 Javascript
JS实现的N多简单无缝滚动代码(包含图文效果)
Nov 06 Javascript
基于Bootstrap使用jQuery实现简单可编辑表格
May 04 Javascript
基于MVC+EasyUI的web开发框架之使用云打印控件C-Lodop打印页面或套打报关运单信息
Aug 29 Javascript
JavaScript拖动层Div代码
Mar 01 Javascript
详解vue中使用express+fetch获取本地json文件
Oct 10 Javascript
微信小程序开发之路由切换页面重定向问题
Sep 18 Javascript
jQuery设置下拉框显示与隐藏效果的方法分析
Sep 15 jQuery
vue elementUI 表单校验的实现代码(多层嵌套)
Nov 06 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游戏编程25个脚本代码
2011/02/08 PHP
PHP explode()函数用法、切分字符串
2012/10/03 PHP
thinkphp常见路径用法分析
2014/12/02 PHP
Javascript之文件操作
2007/03/07 Javascript
jQuery的写法不同导致的兼容性问题的解决方法
2010/07/29 Javascript
19个很有用的 JavaScript库推荐
2011/06/27 Javascript
JavaScript Memoization 让函数也有记忆功能
2011/10/27 Javascript
jquery.messager.js插件导致页面抖动的解决方法
2013/07/14 Javascript
javascript实现日期按月份加减
2015/05/15 Javascript
js精美的幻灯片画集特效代码分享
2015/08/29 Javascript
JS无缝滚动效果实现方法分析
2016/12/21 Javascript
写给小白看的JavaScript异步
2017/11/29 Javascript
react native 文字轮播的实现示例
2018/07/27 Javascript
深入了解JavaScript 私有化
2019/05/30 Javascript
JS实现电脑虚拟键盘的操作
2020/06/24 Javascript
Vue如何提升首屏加载速度实例解析
2020/06/25 Javascript
Python实现删除Android工程中的冗余字符串
2015/01/19 Python
在Python编程过程中用单元测试法调试代码的介绍
2015/04/02 Python
Django中实现点击图片链接强制直接下载的方法
2015/05/14 Python
Python打包文件夹的方法小结(zip,tar,tar.gz等)
2016/09/18 Python
根据DataFrame某一列的值来选择具体的某一行方法
2018/07/03 Python
Python多线程处理实例详解【单进程/多进程】
2019/01/30 Python
Python多线程模块Threading用法示例小结
2019/11/09 Python
基于Python中的yield表达式介绍
2019/11/19 Python
详解Pandas 处理缺失值指令大全
2020/07/30 Python
详解HTML5 录音的踩坑之旅
2017/12/26 HTML / CSS
EVE LOM英国官网:全世界最好的洁面膏
2017/10/30 全球购物
凯撒娱乐:Caesars Entertainment
2018/02/23 全球购物
美国领先的男士和女士内衣购物网站:Freshpair
2019/02/25 全球购物
科技活动周标语
2014/10/08 职场文书
企业员工辞职信范文
2015/05/12 职场文书
培训班开班主持词
2015/07/02 职场文书
奠基仪式致辞
2015/07/30 职场文书
班组长如何制订适合本班组的工作计划?
2019/07/10 职场文书
Python爬虫中urllib3与urllib的区别是什么
2021/07/21 Python
用JS创建一个录屏功能
2021/11/11 Javascript