在远程站点iFrame中嵌入Reactjs

时间:2018-04-03 09:41:24

标签: javascript reactjs widget

  

已更新为Bounty

     

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

     

我正在寻找的最佳解决方案是编写我的bundle.js   与iframe或simliar解决方案一起进入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来创建我的反应文件(这是我学习的唯一方式。)

4 个答案:

答案 0 :(得分:2)

要满足同源策略(防止CORS错误),请设置<iframe>的{​​{1}}属性,而不是尝试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>";

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

演示:

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

答案 1 :(得分:0)

为了安全起见,嵌入iframe不是一个好习惯,如果你使用沙盒iframe可能会更好。

答案 2 :(得分: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。

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

如果仍然会导致问题并且您需要通过src加载它,您可以让react应用程序检查它是否不在框架内并自行查杀或在没有框架的情况下返回How to identify if a webpage is being loaded inside an iframe or directly into the browser window? < / p>

答案 3 :(得分:0)

您已将root用作index.js中的目标容器。可能这不是index.html文件中DOM元素的名称。使其相同,可能会起作用。