来自 iFrame 的 getBoundingClientRect
Posted
技术标签:
【中文标题】来自 iFrame 的 getBoundingClientRect【英文标题】:getBoundingClientRect from within iFrame 【发布时间】:2018-10-30 03:05:27 【问题描述】:我有一个函数来评估元素(iFrame)是否在视口内,如果元素在视图中,则返回 true。
function isElementInViewport()
var el = document.getElementById('postbid_if')
var rect = el.getBoundingClientRect();
var elemTop = rect.top;
var elemBottom = rect.bottom;
console.log("eleTom " + elemTop)
console.log("elemBottom " + elemBottom)
console.log("window.innerHeight " + (window.innerHeight + (window.top.innerHeight * 0.5)))
var isVisible = (elemTop >= 0) && (elemBottom <= (window.innerHeight + window.innerHeight * 0.5));
return isVisible;
当直接在页面上提供时,此函数可以正常工作,但在实时环境中,当此函数运行时,它位于 iFrame 内,看起来getBoundingClientRect()
引用的是 iFrame 的视口而不是主窗口?
有什么方法可以在带有getBoundingClientRect()
的 iFrame 中使用主窗口视口
【问题讨论】:
【参考方案1】:每个 iframe 都有自己的范围,因此 iframe 内的窗口与 root 窗口不同。
您可以通过window.top
获取根窗口,并根据这些知识计算当前 iframe 的绝对位置。这是一个适当的功能:
function currentFrameAbsolutePosition()
let currentWindow = window;
let currentParentWindow;
let positions = [];
let rect;
while (currentWindow !== window.top)
currentParentWindow = currentWindow.parent;
for (let idx = 0; idx < currentParentWindow.frames.length; idx++)
if (currentParentWindow.frames[idx] === currentWindow)
for (let frameElement of currentParentWindow.document.getElementsByTagName('iframe'))
if (frameElement.contentWindow === currentWindow)
rect = frameElement.getBoundingClientRect();
positions.push(x: rect.x, y: rect.y);
currentWindow = currentParentWindow;
break;
return positions.reduce((accumulator, currentValue) =>
return
x: accumulator.x + currentValue.x,
y: accumulator.y + currentValue.y
;
, x: 0, y: 0 );
现在在isElementInViewport
内更改这些行:
var elemTop = rect.top;
var elemBottom = rect.bottom;
到
var currentFramePosition = getCurrentFrameAbsolutePosition();
var elemTop = rect.top + currentFramePosition.y;
var elemBottom = rect.bottom + currentFramePosition.y;
这应该可行。
【讨论】:
ofc,这不包括安全框架,因为您无权访问父窗口 是的,这是真的。并且没有其他可能做到这一点。【参考方案2】:这是跨域 iframe的代码:
window.addEventListener('message', async (event) =>
if (event.data.channel !== GET_IFRAME_COORDINATES_MESSAGE) return;
const coordinates = window === window.top
? x: 0, y: 0
: await getFrameCoordinates();
const iframes = document.getElementsByTagName('iframe');
for (const iframe of iframes)
if (iframe.src !== event.data.href) continue;
const x, y = iframe.getBoundingClientRect();
event.source.postMessage(
channel: `$GET_IFRAME_COORDINATES_MESSAGE-reply`,
coordinates:
x: coordinates.x + x,
y: coordinates.y + y,
, '*');
break;
);
async function getFrameCoordinates()
return new Promise((resolve, reject) =>
const listenForFrameCoordinatesResponse = (event) =>
if (event.data.channel !== `$GET_IFRAME_COORDINATES_MESSAGE-reply`) return;
window.removeEventListener('message', listenForFrameCoordinatesResponse);
resolve(event.data.coordinates);
;
window.addEventListener('message', listenForFrameCoordinatesResponse);
window.parent.postMessage(
channel: GET_IFRAME_COORDINATES_MESSAGE,
href: window.location.href,
, '*');
setTimeout(() => reject(new Error('Getting frame coordinates timeout')), 2000);
);
【讨论】:
GET_IFRAME_COORDINATES_MESSAGE
是什么?
@Alex,它只是一个任意常量字符串(频道名称)以上是关于来自 iFrame 的 getBoundingClientRect的主要内容,如果未能解决你的问题,请参考以下文章
来自 iFrame 的 getBoundingClientRect
使 document.ready 考虑来自外部 iframe 的元素