JavaScript中計(jì)算網(wǎng)頁中某個(gè)元素的位置
由于項(xiàng)目的需要,測試中需要對網(wǎng)頁元素進(jìn)行截圖,以確保它看上去沒有問題。之前我寫過一篇文章介紹過一種方法,先使用 WebDriver 進(jìn)行全屏截圖,然后根據(jù)目標(biāo)元素(DOM Element)所在的位置,再對截下來的圖片進(jìn)行剪裁,保留我們需要的位置即可。
那段代碼一直都工作得很好,直到我知道了一個(gè)東西:iframe。iframe(普通的 frame 也是一樣的,不過 frame 現(xiàn)在不太常見,這里只用 iframe 舉例)中的內(nèi)容被視為一個(gè)獨(dú)立的網(wǎng)頁,連 Window 對象也是和它的父級網(wǎng)頁分開的。而 WebDriver 中的 WebElement.getLocation()方法只能返回這個(gè) WebElement 和它所在的 Window 的位置關(guān)系,它的實(shí)現(xiàn)沒什么問題,但全屏截圖不僅包含了 iframe 的內(nèi)容,可能也包含了它的父級頁面的內(nèi)容,剪裁的時(shí)候需要知道目標(biāo)元素在截圖中的位置。那么問題來了,挖掘機(jī)技術(shù)哪家強(qiáng)?如何計(jì)算一個(gè)元素相對于截圖的位置?
這個(gè)問題還要分類討論,原因是:Chrome 和 Firefox 中截圖的行為是不一樣的。Chrome 的截圖是當(dāng)前可見(viewport)的網(wǎng)頁內(nèi)容,比方說,當(dāng)網(wǎng)頁的實(shí)際大小超過 Chrome 窗口大小時(shí),根據(jù)滾動條的位置不同,窗口中顯示的內(nèi)容不同,Chrome 的截圖就是顯示出來的內(nèi)容。于是我們要計(jì)算目標(biāo)元素相對于當(dāng)前可見內(nèi)容的位置。而 Firefox 用了一個(gè)方法,可以截到整個(gè)網(wǎng)頁的內(nèi)容,無視當(dāng)前窗口大小。于是對于 Firefox 我們要計(jì)算元素的絕對位置(Absolute Position)。
獲得一個(gè)元素的位置,需要用到一個(gè)方法:Element.getBoundingClientRect()。這個(gè)方法返回這個(gè)元素相對于它所處的 Windows 在當(dāng)前可見內(nèi)容的位置,用 top、left、right、bottom 四個(gè)值來表示。我們只關(guān)心其中的 top 和 left,至于剪裁的尺寸,我們可以通過元素本身的長和寬來得到,不需要計(jì)算。要計(jì)算目標(biāo)元素對于頂級 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 中,我們還需要計(jì)算元素的絕對位置。這里需要用到 Window.pageXOffset。pageXOffset,或者 scrollX,表示當(dāng)前 Window 的橫向滾動條滾動的位置,把這個(gè)值和上述的 left 相加,即可得到目標(biāo)元素的橫向絕對位置。當(dāng)然,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 中需要一些特殊處理,即代碼中標(biāo)注“IE8”的部分。把這兩段 Javascript 代碼,替換之前文中的 WebElement.getLocation(),即可實(shí)現(xiàn)在 iframe 中對特定元素截圖。
相關(guān)文章
在Node.js中使用Javascript Generators詳解
下面小編就為大家?guī)硪黄贜ode.js中使用Javascript Generators詳解。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考2016-05-05
微信小程序利用for循環(huán)解決內(nèi)容變更問題
這篇文章主要介紹了微信小程序利用for循環(huán)解決內(nèi)容變更問題 ,本文分步驟通過實(shí)例代碼詳解給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03
js 調(diào)用本地exe的例子(支持IE內(nèi)核的瀏覽器)
js 調(diào)用本地exe程序.我實(shí)驗(yàn)了一下 : 使用IE內(nèi)核的瀏覽器 都支持 火狐好像不行,感興趣的碰可以研究下2012-12-12

