详解原生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 相关文章推荐
通过jquery实现tab标签浏览效果
Feb 20 Javascript
Javascript-Mozilla和IE中的一个函数直接量的问题分析
Aug 12 Javascript
ajax上传时参数提交不更新等相关问题
Dec 11 Javascript
深入解读JavaScript中的Hoisting机制
Aug 12 Javascript
详解微信小程序 相对定位和绝对定位
May 11 Javascript
JS实现电商放大镜效果
Aug 24 Javascript
JS限制输入框输入的实现代码
Jul 02 Javascript
mpvue将vue项目转换为小程序
Sep 30 Javascript
详解vue移动端项目代码拆分记录
Mar 15 Javascript
一文读懂ES7中的javascript修饰器
May 06 Javascript
TensorFlow.js 微信小程序插件开始支持模型缓存的方法
Feb 21 Javascript
详解ES6新增字符串扩张方法includes()、startsWith()、endsWith()
May 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
《神奇女侠:血脉》神力女超人大战犯罪公司
2020/04/09 欧美动漫
六酷社区论坛HOME页清新格调免费版 下载
2007/03/07 PHP
在IIS7.0下面配置PHP 5.3.2运行环境的方法
2010/04/13 PHP
php中static 静态变量和普通变量的区别
2016/12/01 PHP
将HTML自动转为JS代码
2006/06/26 Javascript
javascript 用记忆函数快速计算递归函数
2010/03/15 Javascript
jQuery旋转插件—rotate支持(ie/Firefox/SafariOpera/Chrome)
2013/01/16 Javascript
完美解决IE低版本不支持call与apply的问题
2013/12/05 Javascript
Node.js(安装,启动,测试)
2014/06/09 Javascript
一款基jquery超炫的动画导航菜单可响应单击事件
2014/11/02 Javascript
Knockoutjs 学习系列(一)ko初体验
2016/06/07 Javascript
jQuery监听文件上传实现进度条效果的方法
2016/10/16 Javascript
关于JavaScript中事件绑定的方法总结
2016/10/26 Javascript
使用JS正则表达式 替换括号,尖括号等
2016/11/29 Javascript
对vue.js中this.$emit的深入理解
2018/02/23 Javascript
vue代理和跨域问题的解决
2018/07/18 Javascript
微信小程序上传图片到php服务器的方法
2019/05/23 Javascript
微信小程序登录时如何获取input框中的内容
2019/12/04 Javascript
react实现移动端下拉菜单的示例代码
2020/01/16 Javascript
[47:35]VP vs Pain 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/20 DOTA
Python文件右键找不到IDLE打开项解决办法
2015/06/08 Python
Python编程实现二叉树及七种遍历方法详解
2017/06/02 Python
python3.0 模拟用户登录,三次错误锁定的实例
2017/11/02 Python
tensorflow 获取变量&打印权值的实例讲解
2018/06/14 Python
python中plot实现即时数据动态显示方法
2018/06/22 Python
用Python爬取QQ音乐评论并制成词云图的实例
2019/08/24 Python
详解python os.path.exists判断文件或文件夹是否存在
2020/11/16 Python
印尼穆斯林时尚购物网站:Hijabenka
2016/12/10 全球购物
Intersport西班牙:在线体育商店
2019/11/06 全球购物
门卫班长岗位职责
2013/12/15 职场文书
十岁生日同学答谢词
2014/01/19 职场文书
机关党员2014全国两会学习心得体会
2014/03/10 职场文书
乡镇三项教育实施方案
2014/03/30 职场文书
优秀教师先进个人事迹材料
2014/08/31 职场文书
领导班子个人查摆问题对照检查材料
2014/10/02 职场文书
浅谈Golang 嵌套 interface 的赋值问题
2021/04/29 Golang