详解原生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中类的定义及其方式(《javascript高级程序设计》学习笔记)
Jul 04 Javascript
JavaScript计算字符串中每个字符出现次数的小例子
Jul 02 Javascript
jquery插件lazyload.js延迟加载图片的使用方法
Feb 19 Javascript
JavaScript中Number.NEGATIVE_INFINITY值的使用详解
Jun 05 Javascript
简单讲解AngularJS的Routing路由的定义与使用
Mar 05 Javascript
微信小程序 wx.uploadFile无法上传解决办法
Dec 14 Javascript
JS闭包可被利用的常见场景小结
Apr 09 Javascript
JavaScript纯色二维码变成彩色二维码
Jul 23 Javascript
浅谈手写node可读流之流动模式
Jun 01 Javascript
Vue中的Props(不可变状态)
Sep 29 Javascript
9102了,你还不会移动端真机调试吗
Mar 25 Javascript
微信小程序iOS下拉白屏晃动问题解决方案
Oct 12 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
一款Jquery 分页插件的改造方法(服务器端分页)
2011/07/11 Javascript
解决jquery操作checkbox火狐下第二次无法勾选问题
2014/02/10 Javascript
js跨域请求的5中解决方式
2015/07/02 Javascript
JS实现可点击展开与关闭的左侧广告代码
2015/09/02 Javascript
浅谈Sublime Text 3运行JavaScript控制台
2016/06/06 Javascript
Nodejs中 npm常用命令详解
2016/07/04 NodeJs
利用浮层使select不可选的实现方法
2016/12/03 Javascript
纯js代码生成可搜索选择下拉列表的实例
2018/01/11 Javascript
vue柱状进度条图像的完美实现方案
2019/08/26 Javascript
vue中使用百度脑图kityminder-core二次开发的实现
2019/09/26 Javascript
JavaScript创建表格的方法
2020/04/13 Javascript
vue 动态设置img的src地址无效,npm run build 后找不到文件的解决
2020/07/26 Javascript
解决vant中 tab栏遇到的坑 van-tabs
2020/11/04 Javascript
Vue ​v-model相关知识总结
2021/01/28 Vue.js
利用Python命令行传递实例化对象的方法
2016/11/02 Python
python3使用requests模块爬取页面内容的实战演练
2017/09/25 Python
人脸识别经典算法一 特征脸方法(Eigenface)
2018/03/13 Python
python操作excel的包(openpyxl、xlsxwriter)
2018/06/11 Python
Python Django中间件,中间件函数,全局异常处理操作示例
2019/11/08 Python
python logging添加filter教程
2019/12/24 Python
python列表返回重复数据的下标
2020/02/10 Python
keras 获取某层的输入/输出 tensor 尺寸操作
2020/06/10 Python
试述DBMS的主要功能
2016/11/13 面试题
一套SQL笔试题
2016/08/14 面试题
C#里面可以避免一个类被其他类继承么?如何?
2013/09/26 面试题
护理个人求职信范文
2014/01/08 职场文书
质量主管工作职责
2014/09/26 职场文书
房屋登记授权委托书范本
2014/10/09 职场文书
机关作风建设自查报告
2014/10/22 职场文书
教师党员整改措施
2014/10/24 职场文书
工会2014法制宣传日活动总结
2014/11/01 职场文书
秋季运动会开幕词
2015/01/28 职场文书
世界名著读书笔记
2015/06/25 职场文书
企业廉洁教育心得体会
2016/01/20 职场文书
python中os.path.join()函数实例用法
2021/05/26 Python
Redis主从配置和底层实现原理解析(实战记录)
2021/06/30 Redis