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 相关文章推荐
JS截取字符串常用方法详细整理
Oct 28 Javascript
提取字符串中年月日的函数代码
Nov 05 Javascript
js 阻止子元素响应父元素的onmouseout事件具体实现
Dec 23 Javascript
绑定回车enter事件代码
May 18 Javascript
JS不用正则验证输入的字符串是否为空(包含空格)的实现代码
Jun 14 Javascript
AngularJS基础 ng-model 指令详解及示例代码
Aug 02 Javascript
模拟javascript中的sort排序(简单实例)
Aug 17 Javascript
ajax实现动态下拉框示例
Jan 10 Javascript
AngularJS自定义表单验证功能实例详解
Aug 24 Javascript
微信小程序车牌号码模拟键盘输入功能的实现代码
Nov 11 Javascript
微信小程序自定义导航教程(兼容各种手机)
Dec 12 Javascript
读懂CommonJS的模块加载
Apr 19 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入门学习知识点一 PHP与MYSql连接与查询
2011/07/14 PHP
php变量作用域的深入解析
2013/06/03 PHP
php实现的网页版剪刀石头布游戏示例
2016/11/25 PHP
php 数据结构之链表队列
2017/10/17 PHP
php使用curl伪造来源ip和refer的方法示例
2018/05/08 PHP
redis+php实现微博(三)微博列表功能详解
2019/09/23 PHP
JS操作Cookies包括(读取添加与删除)
2012/12/26 Javascript
选择器中含有空格在使用示例及注意事项
2013/07/31 Javascript
给html超链接设置事件不使用href来完成跳
2014/04/20 Javascript
js获取url中"?"后面的字串方法
2014/05/15 Javascript
jquery 新建的元素事件绑定问题解决方案
2014/06/12 Javascript
jquery uploadify 在FF下无效的解决办法
2014/09/26 Javascript
基于JavaScript实现全屏透明遮罩div层锁屏效果
2016/01/26 Javascript
一个字符串中出现次数最多的字符 统计这个次数【实现代码】
2016/04/29 Javascript
基于JS实现省市联动效果代码分享
2016/06/06 Javascript
微信小程序 页面跳转和数据传递实例详解
2017/01/19 Javascript
js常用的继承--组合式继承
2017/03/06 Javascript
AngularJs点击状态值改变背景色的实例
2017/12/18 Javascript
微信小程序以7天为周期连续签到7天功能效果的示例代码
2020/08/20 Javascript
Python+Turtle动态绘制一棵树实例分享
2018/01/16 Python
Python内存管理实例分析
2019/07/10 Python
Kali Linux安装ipython2 和 ipython3的方法
2019/07/11 Python
python飞机大战 pygame游戏创建快速入门详解
2019/12/17 Python
python之MSE、MAE、RMSE的使用
2020/02/24 Python
Python连接Impala实现步骤解析
2020/08/04 Python
详解使用canvas保存网页为pdf文件支持跨域
2018/11/23 HTML / CSS
html5模拟平抛运动(模拟小球平抛运动过程)
2013/07/25 HTML / CSS
Algenist奥杰尼官网:微藻抗衰老护肤品牌
2017/07/15 全球购物
Pop In A Box英国:Funko POP搪胶公仔
2019/05/27 全球购物
大学生工作推荐信范文
2013/12/02 职场文书
营业员演讲稿
2013/12/30 职场文书
文明餐桌行动实施方案
2014/02/19 职场文书
员工合理化建议书
2014/05/19 职场文书
白酒营销策划方案
2014/08/17 职场文书
大学生军训自我鉴定范文
2014/09/18 职场文书
入伍通知书
2015/04/23 职场文书