详解原生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
IE6下javasc#ipt:void(0) 无效的解决方法
Dec 23 Javascript
AngularJS学习笔记之基本指令(init、repeat)
Jun 16 Javascript
详解AngularJS中的表达式使用
Jun 16 Javascript
jquery+html5烂漫爱心表白动画代码分享
Aug 24 Javascript
Vue.js 2.0 移动端拍照压缩图片上传预览功能
Mar 06 Javascript
详解Vue.js 2.0 如何使用axios
Apr 21 Javascript
小发现之浅谈location.search与location.hash的问题
Jun 23 Javascript
JS点击动态添加标签、删除指定标签的代码
Apr 18 Javascript
详解JavaScript的内存空间、赋值和深浅拷贝
Apr 17 Javascript
JS实现时间校验的代码
May 25 Javascript
vue同个按钮控制展开和折叠同个事件操作
Jul 29 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类与对象中的private访问控制的疑问
2012/11/01 PHP
PHP调用.NET的WebService 简单实例
2015/03/27 PHP
CI框架(CodeIgniter)公共模型类定义与用法示例
2017/08/10 PHP
深入理解PHP的远程多会话调试
2017/09/21 PHP
不常用但很实用的PHP预定义变量分析
2019/06/25 PHP
javascript document.execCommand() 常用解析
2009/12/14 Javascript
P3P Header解决Cookie跨域的问题
2013/03/12 Javascript
jQuery DOM删除节点操作指南
2015/03/03 Javascript
javascript中关于&& 和 || 表达式的小技巧分享
2015/04/10 Javascript
JS模式之简单的订阅者和发布者模式完整实例
2015/06/30 Javascript
jquery实现的淡入淡出下拉菜单效果
2015/08/25 Javascript
详谈Angular路由与Nodejs路由的区别
2017/03/05 NodeJs
Angular4.x通过路由守卫进行路由重定向实现根据条件跳转到相应的页面(推荐)
2018/05/10 Javascript
vue 实现Web端的定位功能 获取经纬度
2019/08/08 Javascript
纯异步nodejs文件夹(目录)复制功能
2019/09/03 NodeJs
layui清空,重置表单数据的实例
2019/09/12 Javascript
单线程JavaScript实现异步过程详解
2020/05/19 Javascript
Python中list初始化方法示例
2016/09/18 Python
python计算auc指标实例
2017/07/13 Python
在PYQT5中QscrollArea(滚动条)的使用方法
2019/06/14 Python
python 正则表达式参数替换实例详解
2020/01/17 Python
Python : turtle色彩控制实例详解
2020/01/19 Python
简单了解django文件下载方式
2020/02/10 Python
python实现查找所有程序的安装信息
2020/02/18 Python
利用CSS3把图片变成灰色模式的实例代码
2016/09/06 HTML / CSS
Farfetch台湾官网:奢侈品牌时尚购物平台
2019/06/17 全球购物
开水果连锁店创业计划书
2013/12/29 职场文书
普通简短的个人自我评价
2014/02/15 职场文书
电气工程及其自动化专业毕业生自荐信
2014/06/21 职场文书
优秀团员事迹材料1000字
2014/08/20 职场文书
十八大观后感
2015/06/12 职场文书
自荐信大全
2019/03/21 职场文书
MybatisPlus EntityWrapper如何自定义SQL
2022/03/22 Java/Android
【海涛解说】史上最给力比赛,挑战DOTA极限
2022/04/01 DOTA
使用Python通过企业微信应用给企业成员发消息
2022/04/18 Python
利用nginx搭建RTMP视频点播、直播、HLS服务器
2022/05/25 Servers