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 相关文章推荐
Javascript的闭包
Dec 31 Javascript
javascript中关于break,continue的特殊用法与介绍
May 24 Javascript
通过Javascript创建一个选择文件的对话框代码
Jun 16 Javascript
使用控制台破解百小度一个月只准改一次名字
Aug 13 Javascript
Javascript 函数的四种调用模式
Nov 05 Javascript
js实现适合新闻类图片的轮播效果
Feb 05 Javascript
js排序与重组的实例讲解
Aug 28 Javascript
使用原生js封装的ajax实例(兼容jsonp)
Oct 12 Javascript
js实现左右两侧浮动广告
Jul 09 Javascript
详解搭建一个vue-cli的移动端H5开发模板
Jan 17 Javascript
vue 解决provide和inject响应的问题
Nov 12 Javascript
vue实现树状表格效果
Dec 29 Vue.js
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实现下载生成某链接快捷方式的解决方法
2013/05/07 PHP
PHP实现GIF图片验证码
2015/11/04 PHP
php使用crypt()函数进行加密
2017/06/08 PHP
PHP上传图片到数据库并显示的实例代码
2019/12/20 PHP
javascript移出节点removeChild()使用介绍
2014/04/03 Javascript
js 截取或者替换字符串中的数字实现方法
2016/06/13 Javascript
对Js OOP编程 创建对象的一些全面理解
2016/07/26 Javascript
jQuery ajax MD5实现用户注册即时验证功能
2016/10/11 Javascript
微信小程序 toast 详解及实例代码
2016/11/09 Javascript
vue-router:嵌套路由的使用方法
2017/02/21 Javascript
Angular2学习教程之组件中的DOM操作详解
2017/05/28 Javascript
JS获取字符对应的ASCII码实例
2017/09/10 Javascript
基于jquery.page.js实现分页效果
2018/01/01 jQuery
vue+elementUi图片上传组件使用详解
2019/08/20 Javascript
js使用文档就绪函数动态改变页面内容示例【innerHTML、innerText】
2019/11/07 Javascript
python装饰器-限制函数调用次数的方法(10s调用一次)
2018/04/21 Python
解决python爬虫中有中文的url问题
2018/05/11 Python
python学习笔记--将python源文件打包成exe文件(pyinstaller)
2018/05/26 Python
Window环境下Scrapy开发环境搭建
2018/11/18 Python
深入浅析python 协程与go协程的区别
2019/05/09 Python
Django网络框架之创建虚拟开发环境操作示例
2019/06/06 Python
Python实现语音识别和语音合成功能
2019/09/20 Python
python实现提取COCO,VOC数据集中特定的类
2020/03/10 Python
利用canvas实现图片压缩的示例代码
2018/07/17 HTML / CSS
美国在线宠物用品商店:Entirely Pets
2017/01/01 全球购物
美国隐形眼镜零售商:LensPure
2019/03/10 全球购物
德国足球商店:OUTFITTER
2019/05/06 全球购物
探索欧洲最好的品牌:Bombinate
2019/06/14 全球购物
商务英语专业求职信范文
2014/01/28 职场文书
英语课前三分钟演讲稿(6篇)
2014/09/13 职场文书
党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
2015年南京大屠杀纪念日活动总结
2015/03/24 职场文书
2016年大学生党员公开承诺书
2016/03/24 职场文书
导游词之西递宏村
2019/12/10 职场文书
MySQL表字段时间设置默认值
2021/05/13 MySQL
pytorch 实现在测试的时候启用dropout
2021/05/27 Python