【问题标题】:Embedding Reactjs in Remote Site iFrame在远程站点 iFrame 中嵌入 Reactjs
【发布时间】:2018-09-12 14:12:01
【问题描述】:

赏金更新

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

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

我正在探索如何使用 React 来制作一个可嵌入的小部件,所以我从谷歌搜索中得到了以下信息。但是,my 不呈现,并返回以下消息。

错误信息 [错误] Invariant Violation:目标容器不是 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 创建我的反应文件(这是我学习的唯一方法。)

【问题讨论】:

  • 我以后有时间也许可以帮忙。
  • 如果您还需要帮助?
  • 我现在只是将 react 应用页面设置为 src。不确定这是否是正确的方法。我必须找到隐藏网址的方法,以便网页只能在 iframe 中加载
  • @Eduard 显然,我添加 src 的解决方案有一个缺点,就是让用户可以方便地在新窗口中打开应用程序,这是我们想要避免的。任何解决方案表示赞赏。添加赏金。
  • 为什么在新窗口中打开不好,特别是如果用户必须右键单击并从菜单中明确选择它?

标签: javascript reactjs widget


【解决方案1】:

要满足同源策略(防止 CORS 错误),请设置 &lt;iframe&gt;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>";

【讨论】:

  • 嗨,它仍然没有加载应用程序。
  • @SomeoneSpecial JavaScript 控制台说什么?您是否对其进行了修改,使其加载应用程序而不是 Example content
【解决方案2】:

出于安全考虑,嵌入 iframe 并不是一个好的做法,如果您使用沙盒 iframe 可能会更好。

【讨论】:

    【解决方案3】:

    在您的测试环境中,在目标 div 被读取到 DOM 之前,脚本会触发,只需更改标签的顺序即可。请参阅下文并查看底部,了解您尝试执行的操作在迁移到野外时可能会导致的其他问题。

    将“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?

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-24
        相关资源
        最近更新 更多