在远程站点iFrame中嵌入Reactjs

问题描述 投票:6回答:4

更新为Bounty

我目前在我的iframe中使用src =“url”来加载对我来说不是最佳的ReactApp,因为这将允许用户右键单击并“在新窗口中打开”。

我正在寻找的最佳解决方案是将我的bundle.js与一个或类似的解决方案一起写入iframe。 src将保持为空白,因此用户无法在新窗口/选项卡中右键单击以打开。

我正在探索如何使用React制作一个可嵌入的小部件,所以我到目前为止从google搜索到了以下内容。但是,我不渲染,并返回以下消息。

错误消息[错误]不变违规:目标容器不是DOM元素。

我使用create-react-app为我的嵌入式应用程序,我只有2个简单的文件。

index.js

import React from 'react';
import ReactDom from 'react-dom';
import App from './App';

ReactDom.render(
        <App />, document.getElementById('root')
)

App.js

import React, { Component } from 'react';

class App extends Component {
    render() {
        return (
            <div>This is an embedable widget</div>
            )
    }
}

export default App;

我创建了一个test.js,它将在远程iframe中使用下面的简单代码调用以生成html,包含js包,以及包含id的div。

这是test.js

//Creates Div
var d = document.createElement("div");
document.body.appendChild(d);

//Creates iFrame
var n = document.createElement("iframe");
n.id = "microcom-frame";
n.style.width = "100%";
n.style.height = "100%";
n.style.background = "transparent";
n.style.position = "relative";
n.style.margin = 0;
n.style.border = "none";
n.style.overflow ="hidden";
n.style.display = "block";

//Append iFrame inside Div
d.appendChild(n);

//Write content to iFrame
n.contentWindow.document.open("text/html", "replace"), 
n.contentWindow.document.write("\n    <!doctype html>\n    <head><script src='http://localhost:3001/static/js/bundle.js' type='text/javascript'></script></head>\n    <body><div id='root'></div></body>\n    </html>"), 
n.contentWindow.document.close();

现在在远程站点上,我在标题中只有以下脚本来调用上面的test.js。

    <script>
      (function() {
  var d = document,
      h = d.getElementsByTagName('head')[0],
      s = d.createElement('script');

  s.type = 'text/javascript';
  s.async = true;
  s.src = 'http://localhost:3001/test.js';
  h.appendChild(s);

} )();
</script>

这是......

  • test.js加载成功
  • div成功创建
  • iframe创建成功
  • 我可以看到在iframe的标题中添加了bundle.js以及id为root的div

但是,没有显示。

感谢有人可以带我到下一步。我正在使用create-react-app创建我的反应文件(这是我学习的唯一方法。)

javascript reactjs widget
4个回答
2
投票

要满足同源策略(防止CORS错误),请设置<iframe>srcdoc属性,而不是尝试write

n.srcdoc = "\n    <!doctype html>\n    <head><script src='http://localhost:3001/static/js/bundle.js' type='text/javascript'></script></head>\n    <body><div id='root'></div></body>\n    </html>";

作为额外的好处,您可以使用以下命令禁用右键单击上下文菜单:

n.contentWindow.document.addEventListener("contextmenu", function(e){
    e.preventDefault();
    return false;
}, false);

这作为一种安全措施是完全没用的,但它只是作为一个红鲱鱼。单独打开框架时显示的页面将不包含内容。只有在用户想要复制的iframe页面中没有任何内容时才能执行此操作;它并没有阻止他们这样做,但如果你想复制一些东西,那真的很烦人。


演示:

//Creates Div
var d = document.createElement("div");
document.body.appendChild(d);

//Creates iFrame
var n = document.createElement("iframe");
n.id = "microcom-frame";
n.style.width = "100%";
n.style.height = "100%";
n.style.background = "transparent";
n.style.position = "relative";
n.style.margin = 0;
n.style.border = "none";
n.style.overflow ="hidden";
n.style.display = "block";

//Append iFrame inside Div
d.appendChild(n);

//Write content to iFrame
n.srcdoc = "<!doctype html><html><head></head><body><div id='root'>Example content</div></body></html>";

0
投票

出于安全目的,嵌入iframe不是一个好习惯,如果使用沙盒iframe可能会更好。


0
投票

在测试环境中的DOM中读取目标div之前的脚本,只需更改标记的顺序即可。请参阅下文并查看底部的其他问题,当您移动到野外时,您可能会尝试做什么。

将“async defer”添加到您在初始代码中插入iframe的脚本标记中,如下所示:

n.contentWindow.document.write("\n    <!doctype html>\n    <head><script async defer src='http://localhost:3001/static/js/bundle.js' type='text/javascript'></script></head>\n    <body><div id='root'></div></body>\n    </html>"),

您可以在您插入的正文的末尾添加脚本标记(或执行展位并将异步延迟放在其上)

尝试使用srcdoc,它工作得更好,因为它甚至没有提供突破框架的选项(它只是重新加载上面示例中的当前位置)

n.srcdoc = "\n    <!doctype html>\n    <head></head>\n    <body><div id='root'></div><script async defer  src='http://localhost:3001/static/js/bundle.js' type='text/javascript'></script></body>\n    </html>"

然而。

当我在生产中尝试这个时,它没有加载我的整个应用程序。除了构建中的/ static文件夹中的初始js包之外的任何其他内容都不会加载,因为应用程序会相对于小部件位置查找它们。

你可以通过确保js没有块来解决这个问题(创建反应应用程序不应该分割你的代码,除非你使用一个包专门做那个)。您还需要在应用程序外部加载所有css文件和图像,而不是导入它们。

也可以使用其中一种方法将react应用程序部署到子目录中,以便为应用程序的静态资源设置绝对基本URL。

另外,您可能希望在使用它时从react应用程序中的index.js中删除registerServiceWorker()。

如果仍然会导致问题并且您需要通过src加载它,您可以让react应用程序检查它是否不在框架内并自行杀死,或者在这里通过某些方法取消框架时返回How to identify if a webpage is being loaded inside an iframe or directly into the browser window?


0
投票

您已在index.js中使用root作为目标容器。可能这不是index.html文件中DOM元素的名称。使它一样,也许它会起作用。

© www.soinside.com 2019 - 2024. All rights reserved.