我遇到了一个困扰整个Google的问题,但是所提供的解决方案均无法正常工作。我认为这些解决方案中的大多数都不考虑跨域。
我有一个网站,我想指示用户使用(整页)iframe嵌入他们的网站。问题仅在某些版本的Safari上存在。 IFrame中的元素无法滚动到视图中。
我注意到,如果我进行相同的域测试,则IFrame可以使用window.parent.scrollTo(0,element.top)
进行滚动。这可行,但不能跨域。另一个奇怪的是,没有其他浏览器需要window.parent方法来滚动IFrame,而仅是Safari。所有其他浏览器都可以在IFrame中使用element.scrollIntoView()
。请注意,我已经使用JavaScript workaround通过跨协议IFrame来取悦Safari。
我仅在IFrame内部的Safari Mobile上看到的另一个问题是,向下滚动时,Bootstrap Modals在IFrame的顶部看不见。虽然,我确定如果可以正确设置滚动位置,那么我们也应该能够设置模式位置。
这就是我尝试过的;
1. window.frames['IFrameName'].document.
getElementById("elmId").scrollIntoView();
(我认为)我最后的选择是在IFrame中使用postMessage来通知父域以设置框架的滚动位置。
在我看来,这个问题已经存在了很长时间。有没有比这更好的方法了?
答案 0 :(得分:1)
这最终导致比代码更多的研究。发生的是-我有一些代码根据内容调整了IFrame的大小。
在所有其他浏览器中,它可以正常工作并消除滚动条。原来Safari automatically sizes the Iframe保留了自己的滚动功能。在我的应用程序中,静态页面为零。这给我留下了无法使用链接中描述的scrolling=no
修复程序的问题。
确切地了解了所发生的情况之后,我采取了另一种方法来修复elm.scrollIntoView()
。该代码是注释,然后是重要部分;
RequiresIframeScrollFix
应用iframe修订elm.getBoundingClientRect().top
从iframe中获取滚动位置。window.parent.postMessage
window.addEventListener('message',...)
在父级中接收邮件这是它的样子。
iframe网站
我们的iframe网站当前将其元素滚动到这样的视图中elm.scrollIntoView();
,我们将其更改为以下内容。
if (RequiresIframeScrollFix())
window.parent.postMessage(elm.getBoundingClientRect().top, "*"); // Tell IFrame parent to do the scrolling. If this is not a test environment, replace "*" with the parent domain.
else
elm.scrollIntoView(); // If not scroll into view as usual.
可选:使用elm.getBoundingClientRect().top
修复了IOS IFrame中的引导模式定位。
$('#modalId').css('top', elm.getBoundingClientRect().top); // This fixes modal not in view on Safari Iframes.
RequiresIframeScrollFix()
主要由一些很好的文档代码组成,这些代码围绕SO来确定我们是否位于IPad或IPhone上的iframe中。
// Used to help identify problematic userAgents.
var debugNavigator = false;
// Detects an issue on mobile where the Parent is an iframe which cannot have it's scroll bars removed.
// Presumably not a bug as safari will autosize it's iframes: https://salomvary.com/iframe-resize-ios-safari.html
// Can use "scrolling=no" fix instead if the parent knows the initial size of your iframe.
function RequiresIframeScrollFix() {
try {
// Debug navigator Agent
if (debugNavigator)
alert(navigator.userAgent);
// We know this issue happens inside an IFrame on;
// Safari iPhone
// Safari iPad
// Safari Desktop Works fine.
// Check for safari
var is_safari = navigator.userAgent.indexOf("Safari") > -1;
// Chrome has Safari in the user agent so we need to filter (https://stackoverflow.com/a/7768006/1502448)
var is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
if ((is_chrome) && (is_safari)) { is_safari = false; }
// If we need to narrow this down even further we can use a more robust browser detection (https://stackoverflow.com/questions/5916900)
// Problematic browsers can be adjusted here.
if (is_safari && inIframe() && (
navigator.userAgent.match(/iPad/i) ||
navigator.userAgent.match(/iPhone/i)
))
return true;
else
return false;
} catch (e) {
alert(e.message);
}
}
// (https://stackoverflow.com/questions/326069/)
function inIframe() {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}
父网站
我们的父站点保存由Safari Mobile自动调整大小的IFrame。因此,父网站现在拥有自己的滚动条,而不是IFrame。我们在父网站内部设置了侦听器,以在其从IFramed网站收到消息时进行滚动。
// Safari Mobile Iframe Cross Domain Scroll Fix.
window.onload = function () {
// Calback function to process our postMessages.
function receiveMessage(e) {
try {
// Set the scroll position from our postMessage data.
// Non-Test pages should uncomment the line below.
//if (e.origin.includes("your-iframe-domain.com"))
window.scrollTo(0, e.data);
}
catch (err) {
}
}
// Setup and event to receives messages form our iframe (or window)
window.addEventListener('message', receiveMessage);
}
希望这可以帮助其他人在移动设备上解决Safari Iframe问题。另外,让我知道是否我忽略了更好的解决方案。
答案 1 :(得分:0)
另一个选项是iframeResizer库。您可以在iframePage中使用两种方法:scrollTo和scrollToOffset,它们的作用与您描述的大致相同-它们通过消息进行通信。它在Safari中为我们解决了这个问题。
在父页面内部,为iframe设置大小调整时,您必须为其onScroll事件分配一个回调函数:
iframeNode.iframeResize({
...,
onScroll: ({x,y}) => callback
}
在iframe页面中:
if('parentIFrame' in window){
window.parentIFrame.scrollTo(0, someNode.offsetTop);
}