使用纯 JS 的跨源 iframe 中的视差效果?
Parallax effect within a cross-origin iframe with pure JS?
所以我有一个包含 iframe
元素的文档。
我的文档和 iframe
的来源不同。
我想让这个iframe
的内容在加载到文档中时看起来像视差。
例如,文档如下所示:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>blah</p>
<p>blah</p>
<p>blah</p>
<p>blah</p>
<iframe src="parallax.html" width="200" height="200">
<p>blah</p>
<p>blah</p>
<p>blah</p>
</body>
</html>
并且 parallax.html 仅包含适合 window 大小的图像。
我认为 parallax.html 应该有脚本来确定 window 相对于屏幕的位置并调整图像位置。我试过一些东西,例如:
- 在顶部添加滚动事件侦听器window,但由于它们是跨域的,因此受到限制
- 得到
document.body.scrollTop
,但总是returns0
- 获取
getBoundingClientRect()
参数,但top
也returns0
这可能吗?我是不是错过了什么?是的,我必须使用 vanilla JS 来实现,没有 jQuery 或其他库。
正如您所注意到的,跨源限制使这有点棘手。您的父框架将无法访问内部变量或在其子框架中设置侦听器,反之亦然。它可以访问的属性集非常有限,可在此处查看:https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Cross-origin_script_API_access
此外,我相信 iframe 中的 document.body.scrollTop
和 getBoundingClientRect()
是相对于框架本身的,就好像框架是一个迷你 window。您可能无法在 iframe 中访问所需的信息,但应该可以从父框架中获取它。
使用 postMessage
跨域框架之间传递信息的传统方式是使用iframe.contentWindow.postmessage
.
在这种情况下,一个简单的实现是将滚动侦听器附加到父框架,父框架将消息发送到子框架。它看起来像这样:
在父文档中:
var iframeElement = document.getElementById('my-parallax'); // give your iframe this id
window.addEventListener('scroll', () => {
var rect = iframeElement.getBoundingClientRect();
var dataToSend = {
scrollY: window.scrollY,
left: rect.left, right: rect.right,
bottom: rect.bottom, top: rect.top
};
var targetOrigin = '*'; // can change this if you know it
iframeElement.contentWindow.postMessage(dataToSend, targetOrigin);
});
然后在parallax.html:
window.addEventListener('message', function (e) {
var data = e.data;
if (e.source === window.parent) { // check if the sender was the parent
// use data.scrollY, data.top... etc. here
}
});
这种方法(以及一般的 postMessage)的警告是不能保证 iframe 的 UI 会与父 window 同步更新。差异应该很小,除非对任一帧进行大量计算。据我所知,这在使用跨域 iframe 时是不可避免的。
所以我有一个包含 iframe
元素的文档。
我的文档和 iframe
的来源不同。
我想让这个iframe
的内容在加载到文档中时看起来像视差。
例如,文档如下所示:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>blah</p>
<p>blah</p>
<p>blah</p>
<p>blah</p>
<iframe src="parallax.html" width="200" height="200">
<p>blah</p>
<p>blah</p>
<p>blah</p>
</body>
</html>
并且 parallax.html 仅包含适合 window 大小的图像。
我认为 parallax.html 应该有脚本来确定 window 相对于屏幕的位置并调整图像位置。我试过一些东西,例如:
- 在顶部添加滚动事件侦听器window,但由于它们是跨域的,因此受到限制
- 得到
document.body.scrollTop
,但总是returns0 - 获取
getBoundingClientRect()
参数,但top
也returns0
这可能吗?我是不是错过了什么?是的,我必须使用 vanilla JS 来实现,没有 jQuery 或其他库。
正如您所注意到的,跨源限制使这有点棘手。您的父框架将无法访问内部变量或在其子框架中设置侦听器,反之亦然。它可以访问的属性集非常有限,可在此处查看:https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Cross-origin_script_API_access
此外,我相信 iframe 中的 document.body.scrollTop
和 getBoundingClientRect()
是相对于框架本身的,就好像框架是一个迷你 window。您可能无法在 iframe 中访问所需的信息,但应该可以从父框架中获取它。
使用 postMessage
跨域框架之间传递信息的传统方式是使用iframe.contentWindow.postmessage
.
在这种情况下,一个简单的实现是将滚动侦听器附加到父框架,父框架将消息发送到子框架。它看起来像这样:
在父文档中:
var iframeElement = document.getElementById('my-parallax'); // give your iframe this id
window.addEventListener('scroll', () => {
var rect = iframeElement.getBoundingClientRect();
var dataToSend = {
scrollY: window.scrollY,
left: rect.left, right: rect.right,
bottom: rect.bottom, top: rect.top
};
var targetOrigin = '*'; // can change this if you know it
iframeElement.contentWindow.postMessage(dataToSend, targetOrigin);
});
然后在parallax.html:
window.addEventListener('message', function (e) {
var data = e.data;
if (e.source === window.parent) { // check if the sender was the parent
// use data.scrollY, data.top... etc. here
}
});
这种方法(以及一般的 postMessage)的警告是不能保证 iframe 的 UI 会与父 window 同步更新。差异应该很小,除非对任一帧进行大量计算。据我所知,这在使用跨域 iframe 时是不可避免的。