详解原生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 相关文章推荐
slice函数的用法 之不错的应用
Dec 29 Javascript
ImageZoom 图片放大镜效果(多功能扩展篇)
Apr 14 Javascript
如何创建一个JavaScript弹出DIV窗口层的效果
Sep 25 Javascript
javascript表单验证使用示例(javascript验证邮箱)
Jan 07 Javascript
javascript控制在光标位置插入文字适合表情的插入
Jun 09 Javascript
js实现新年倒计时效果
Dec 10 Javascript
JS弹性运动实现方法分析
Dec 15 Javascript
Bootstrap免费字体和图标网站(值得收藏)
Mar 16 Javascript
深入研究jQuery图片懒加载 lazyload.js使用方法
Aug 16 jQuery
vue-cli3.0如何使用CDN区分开发、生产、预发布环境
Nov 22 Javascript
vue2.0自定义指令示例代码详解
Apr 25 Javascript
浅谈vue 二级路由嵌套和二级路由高亮问题
Aug 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_Flame(Version:Progress)的原代码
2006/10/09 PHP
使用php+apc实现上传进度条且在IE7下不显示的问题解决方法
2013/04/25 PHP
PHP给前端返回一个JSON对象的实例讲解
2018/05/31 PHP
javascript+iframe 实现无刷新载入整页的代码
2010/03/17 Javascript
JQuery对id中含有特殊字符的转义处理示例
2013/09/06 Javascript
jQuery 浮动导航菜单适合购物商品类型的网站
2014/09/09 Javascript
JavaScript中Function()函数的使用教程
2015/06/04 Javascript
jquery 动态合并单元格的实现方法
2016/08/26 Javascript
Javascript之深入浅出prototype
2017/02/06 Javascript
使用vue.js实现checkbox的全选和多个的删除功能
2017/02/17 Javascript
js实现旋转木马效果
2017/03/17 Javascript
Vue2.0用户权限控制解决方案的示例
2018/02/10 Javascript
微信小程序自定义tab实现多层tab嵌套功能
2018/06/15 Javascript
vue项目每30秒刷新1次接口的实现方法
2018/12/04 Javascript
微信小程序MUI侧滑导航菜单示例(Popup弹出式,左侧滑动,右侧不动)
2019/01/23 Javascript
layui+SSM的数据表的增删改实例(利用弹框添加、修改)
2019/09/27 Javascript
VUE 解决mode为history页面为空白的问题
2019/11/01 Javascript
JavaScript利用键盘码控制div移动
2020/03/19 Javascript
JavaScript 声明私有变量的两种方式
2021/02/05 Javascript
Python使用cx_Oracle模块将oracle中数据导出到csv文件的方法
2015/05/16 Python
发布你的Python模块详解
2016/09/15 Python
python事件驱动event实现详解
2018/11/21 Python
对python内置map和six.moves.map的区别详解
2018/12/19 Python
对Python _取log的几种方式小结
2019/07/25 Python
PyCharm无法识别PyQt5的2种解决方法,ModuleNotFoundError: No module named 'pyqt5'
2020/02/17 Python
Python Selenium截图功能实现代码
2020/04/26 Python
Python自动化操作实现图例绘制
2020/07/09 Python
详解h5页面在不同ios设备上的问题总结
2019/03/01 HTML / CSS
广州一家公司的.NET面试题
2016/06/11 面试题
机关财务管理制度
2014/01/17 职场文书
自我反省检讨书
2014/01/23 职场文书
群众路线教育实践活动批评与自我批评
2014/09/15 职场文书
公司员工宿舍管理制度
2015/08/07 职场文书
四十九个javascript小知识实用技巧
2021/11/20 Javascript
Android开发实现极为简单的QQ登录页面
2022/04/24 Java/Android
TS 类型兼容教程示例详解
2022/09/23 Javascript