详解原生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 对象成员的可见性说明
Oct 16 Javascript
基于jQuery的仿flash的广告轮播代码
Nov 04 Javascript
Javascript字符串对象的常用方法简明版
Jun 26 Javascript
百度地图给map添加右键菜单(判断是否为marker)
Mar 04 Javascript
Node.js的Web模板引擎ejs的入门使用教程
Jun 06 Javascript
jquery实现左右滑动式轮播图
Mar 02 Javascript
ES6教程之for循环和Map,Set用法分析
Apr 10 Javascript
Node.js中的http请求客户端示例(request client)
May 04 Javascript
纯JS实现可用于页码更换的飞页特效示例
May 21 Javascript
详解javascript中的变量提升和函数提升
May 24 Javascript
微信小程序+腾讯地图开发实现路径规划绘制
May 22 Javascript
关于引入vue.js 文件的知识点总结
Jan 28 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 email邮箱正则
2008/10/08 PHP
php重定向的三种方法分享
2012/02/22 PHP
PHP实现ASCII码与字符串相互转换的方法
2017/04/29 PHP
jquery中:input和input的区别分析
2011/07/13 Javascript
script的async属性以非阻塞的模式加载脚本
2013/01/15 Javascript
纯js分页代码(简洁实用)
2013/11/05 Javascript
javascript框架设计之浏览器的嗅探和特征侦测
2015/06/23 Javascript
很不错的两款Bootstrap Icon图标选择组件
2016/01/28 Javascript
javascript时间戳和日期字符串相互转换代码(超简单)
2016/06/22 Javascript
jQuery鼠标移动图片上实现放大效果
2017/06/25 jQuery
深入浅析vue组件间事件传递
2017/12/29 Javascript
vue2.0 兄弟组件(平级)通讯的实现代码
2018/01/15 Javascript
JS数组去重常用方法实例小结【4种方法】
2018/05/28 Javascript
vue js秒转天数小时分钟秒的实例代码
2018/08/08 Javascript
详解@angular/cli 改变默认启动端口两种方式
2018/11/29 Javascript
微信小程序实现文件、图片上传功能
2020/08/18 Javascript
构建Vue大型应用的10个最佳实践(小结)
2019/11/07 Javascript
python实现的简单窗口倒计时界面实例
2015/05/05 Python
Python中方法链的使用方法
2016/02/23 Python
python字符串格式化方式解析
2019/10/19 Python
tensorflow之tf.record实现存浮点数数组
2020/02/17 Python
python中matplotlib实现随鼠标滑动自动标注代码
2020/04/23 Python
深入浅析Python代码规范性检测
2020/07/31 Python
美国南部最大的家族百货公司:Belk
2017/01/30 全球购物
一套带网友答案的.NET笔试题
2016/12/06 面试题
师范应届生教师求职信
2013/11/05 职场文书
车祸赔偿收入证明
2014/01/09 职场文书
网上蛋糕店创业计划书
2014/01/24 职场文书
科长竞争上岗演讲稿
2014/05/12 职场文书
2014年酒店前台工作总结
2014/11/14 职场文书
家长学校教学计划
2015/01/19 职场文书
拉贝日记观后感
2015/06/05 职场文书
安全教育观后感
2015/06/17 职场文书
电子表的操作介绍说明书
2019/10/28 职场文书
25句企业管理语录:助你迅速打开思路,句句经典!
2020/01/14 职场文书
浅谈resultMap的用法及关联结果集映射
2021/06/30 Java/Android