JavaScript中计算网页中某个元素的位置


Posted in Javascript onJune 10, 2015

由于项目的需要,测试中需要对网页元素进行截图,以确保它看上去没有问题。之前我写过一篇文章介绍过一种方法,先使用 WebDriver 进行全屏截图,然后根据目标元素(DOM Element)所在的位置,再对截下来的图片进行剪裁,保留我们需要的位置即可。

那段代码一直都工作得很好,直到我知道了一个东西:iframe。iframe(普通的 frame 也是一样的,不过 frame 现在不太常见,这里只用 iframe 举例)中的内容被视为一个独立的网页,连 Window 对象也是和它的父级网页分开的。而 WebDriver 中的 WebElement.getLocation()方法只能返回这个 WebElement 和它所在的 Window 的位置关系,它的实现没什么问题,但全屏截图不仅包含了 iframe 的内容,可能也包含了它的父级页面的内容,剪裁的时候需要知道目标元素在截图中的位置。那么问题来了,挖掘机技术哪家强?如何计算一个元素相对于截图的位置?

这个问题还要分类讨论,原因是:Chrome 和 Firefox 中截图的行为是不一样的。Chrome 的截图是当前可见(viewport)的网页内容,比方说,当网页的实际大小超过 Chrome 窗口大小时,根据滚动条的位置不同,窗口中显示的内容不同,Chrome 的截图就是显示出来的内容。于是我们要计算目标元素相对于当前可见内容的位置。而 Firefox 用了一个方法,可以截到整个网页的内容,无视当前窗口大小。于是对于 Firefox 我们要计算元素的绝对位置(Absolute Position)。

获得一个元素的位置,需要用到一个方法:Element.getBoundingClientRect()。这个方法返回这个元素相对于它所处的 Windows 在当前可见内容的位置,用 top、left、right、bottom 四个值来表示。我们只关心其中的 top 和 left,至于剪裁的尺寸,我们可以通过元素本身的长和宽来得到,不需要计算。要计算目标元素对于顶级 Window的位置,我们只需要依次加上它的父级 Window的 top 和 left 即可。代码如下:

function calcViewportLocation(element) {
 var currentWindow = window;
 var rect = element.getBoundingClientRect(); // 元素的位置
 var top = rect.top;
 var left = rect.left;
 while (currentWindow.frameElement != null) { // 处理父级 Window
  element = currentWindow.frameElement;
  currentWindow = currentWindow.parent;
  rect = element.getBoundingClientRect();
  if (rect.top > 0) { top += rect.top; }
  if (rect.left > 0) { left += rect.left; }
 }
 return [Math.round(top), Math.round(left)];
}

以上代码适用于 Chrome ,而在 Firefox 中,我们还需要计算元素的绝对位置。这里需要用到 Window.pageXOffset。pageXOffset,或者 scrollX,表示当前 Window 的横向滚动条滚动的位置,把这个值和上述的 left 相加,即可得到目标元素的横向绝对位置。当然,iframe 也可以特殊处理的:

function calcAbsolutLocation(element) {
 var top = 0;
 var left = 0;
 var currentWindow = window;
 while (element != null) {
  rect = element.getBoundingClientRect();
  var pageYOffset = currentWindow.pageYOffset;
  var pageXOffset = currentWindow.pageXOffset;
  if (typeof pageYOffset === 'undefined') { // IE8
   currentDocument = currentWindow.document;
   var bodyElement = (currentDocument.documentElement
     || currentDocument.body.parentNode || currentDocument.body);
   pageYOffset = bodyElement.scrollTop;
   pageXOffset = bodyElement.scrollLeft;
  }
  top += rect.top + pageYOffset;
  left += rect.left + pageXOffset;
  element = currentWindow.frameElement;
  currentWindow = currentWindow.parent;
  if (element != null) {
   style = window.getComputedStyle(element);
   top += parseInt(style.borderTopWidth, 10);
   left += parseInt(style.borderLeftWidth, 10);
  }
 }
 return [Math.round(top), Math.round(left)];
}

由于 IE8 不支持 pageXOffset 和 scrollX,于是在 IE8 中需要一些特殊处理,即代码中标注“IE8”的部分。把这两段 Javascript 代码,替换之前文中的 WebElement.getLocation(),即可实现在 iframe 中对特定元素截图。

Javascript 相关文章推荐
延时重复执行函数 lLoopRun.js
May 08 Javascript
基于jquery的15款幻灯片插件
Apr 10 Javascript
表单元素的submit()方法和onsubmit事件应用概述
Feb 01 Javascript
基于jquery实现的文字淡入淡出效果
Nov 14 Javascript
JS判断是否360安全浏览器极速内核的方法
Jan 29 Javascript
JavaScript中判断数据类型的方法总结
May 24 Javascript
js 发布订阅模式的实例讲解
Sep 10 Javascript
jQuery+CSS实现的table表格行列转置功能示例
Jan 08 jQuery
微信小程序获取用户openid的实现
Dec 24 Javascript
Vue 动态路由的实现及 Springsecurity 按钮级别的权限控制
Sep 05 Javascript
js实现滑动滑块验证登录
Jul 24 Javascript
微信小程序实现聊天室
Aug 21 Javascript
JavaScript实现强制重定向至HTTPS页面
Jun 10 #Javascript
详解JavaScript中getFullYear()方法的使用
Jun 10 #Javascript
JavaScript中判断函数、变量是否存在
Jun 10 #Javascript
Javascript中实现String.startsWith和endsWith方法
Jun 10 #Javascript
Javascript中判断对象是否为空
Jun 10 #Javascript
javascript事件委托的方式绑定详解
Jun 10 #Javascript
个人总结的一些JavaScript技巧、实用函数、简洁方法、编程细节
Jun 10 #Javascript
You might like
一个简洁实用的PHP缓存类完整实例
2014/07/26 PHP
php四种定界符详解
2017/02/16 PHP
JavaScript 变量基础知识
2009/11/07 Javascript
JavaScript 常见对象类创建代码与优缺点分析
2009/12/07 Javascript
prettify 代码高亮着色器google出品
2010/12/28 Javascript
网站如何做到完全不需要jQuery也可以满足简单需求
2013/06/27 Javascript
window.onload与$(document).ready()的区别分析
2015/05/30 Javascript
jQuery+php实时获取及响应文本框输入内容的方法
2016/05/24 Javascript
详解JavaScript对象类型
2016/06/16 Javascript
jQuery插件扩展测试实例
2016/06/21 Javascript
JavaScript制作颜色反转小游戏
2016/09/25 Javascript
常用JS图片滚动(无缝、平滑、上下左右滚动)代码大全(推荐)
2016/12/20 Javascript
Vue 2.0在IE11中打开项目页面空白的问题解决
2017/07/16 Javascript
jQuery 实现左右两侧菜单添加、移除功能
2018/01/02 jQuery
解决vue select当前value没有更新到vue对象属性的问题
2018/08/30 Javascript
解决vue attr取不到属性值的问题
2018/09/18 Javascript
基于VUE实现的九宫格抽奖功能
2018/09/30 Javascript
微信小程序实现授权登录
2019/05/15 Javascript
[01:53]DOTA2超级联赛专访Zhou 五年职业青春成长
2013/05/29 DOTA
[34:10]Secret vs VG 2019国际邀请赛淘汰赛 败者组 BO3 第二场 8.24
2019/09/10 DOTA
python基础教程之分支、循环简单用法
2016/06/16 Python
Python处理PDF及生成多层PDF实例代码
2017/04/24 Python
Python+matplotlib绘制不同大小和颜色散点图实例
2018/01/19 Python
python 脚本生成随机 字母 + 数字密码功能
2018/05/26 Python
用Python获取摄像头并实时控制人脸的实现示例
2019/07/11 Python
python求绝对值的三种方法小结
2019/12/04 Python
django实现HttpResponse返回json数据为中文
2020/03/27 Python
基于python判断字符串括号是否闭合{}[]()
2020/09/21 Python
Python 使用SFTP和FTP实现对服务器的文件下载功能
2020/12/17 Python
CSS3 伪类选择器 nth-child()说明
2010/07/10 HTML / CSS
家庭户外服装:Hawkshead
2017/11/02 全球购物
列车长先进事迹材料
2014/01/25 职场文书
安全生产网格化管理实施方案
2014/03/01 职场文书
2016年春节慰问信息
2015/03/25 职场文书
Python实现DBSCAN聚类算法并样例测试
2021/06/22 Python
nginx设置资源请求目录的方式详解
2022/05/30 Servers