簡體   English   中英

從 React 中的外部腳本使用 document.write 編寫 HTML 內容

[英]Writing HTML content with document.write from external script in React

我嘗試了多種方法,我正在嘗試從 tryhackme 集成我的橫幅,或者讓我們說從任何平台我們得到一個我們想要集成的腳本 src 但 react 沒有渲染它。

<script src="https://tryhackme.com/badge/170258"></script>

這是我的 reactjs 代碼塊

import React, { Component } from "react";

// const Awards = (props) => {
//     return (
//         <Container>
//             <div>
            
//             {/* <img src="https://tryhackme-badges.s3.amazonaws.com/rootsid.png" alt="TryHackMe"></img> */}
//             </div>
//         </Container>
//     )
// }

// const Container = styled.main`
//     color: white;
// `;

export default class Awards extends Component {
    componentDidMount() {
      const script = document.createElement("script");
  
      script.src = "https://tryhackme.com/badge/170258";
      script.async = true;
      
      var scripttag = document.getElementById('scriptTarget')
      scripttag.appendChild(script);
    }
  
    render() {
      return (
        <div>
          <div id="scriptTarget" />
          <div className="main">
            // Other stuff
          </div>
        </div>
      );
    }
  }

我試圖在 react js 中包含腳本標記,而不是圖像 src,因此它可以是動態的。 我試過helmetreact-safe但無法讓它工作。 這也是小提琴鏈接。

https://jsfiddle.net/h2x5pkfy/

終於設法讓它工作了! 首先,該腳本僅包含一個表達式: document.write(window.atob(<BASE64 encoded content forming a HTML subtree>))

讓 React 加載腳本

建議鏈接中的解決方案有效,只是允許外部腳本寫入您的文檔並不簡單。

問題和想法

執行此操作時收到的錯誤是170258:1 Failed to execute 'write' on 'Document': It isn't possible to write into a document from an asynchronously-loaded external script unless it is explicitly opened. . write文檔write需要打開和關閉已加載的文檔,例如

document.open()
document.write(...)
document.close()

...它還說這是在加載的document.write上使用document.write時隱式完成的,但是,錯誤消息說它必須是外部腳本時的顯式調用。 盡管如此,如果腳本加載並執行,它會覆蓋整個頁面,從而刪除 React 應用程序......使用 React 加載一個刪除 React 的腳本似乎有點奇怪。

由於 OP 無法修改原始腳本並插入必要的調用(不確定這是否足夠),因此這不是一個選項。 一種想法是嘗試將腳本作為文本導入,然后提取 Base64 編碼的字符串並在內部使用它(這會起作用)。 盡管如此,因為它會刪除 React 應用程序,所以我真的不明白這一點。

解決方案:iFrame

為了不執行一些奇怪的 hack 並保持 React 應用程序到位,可以使用 iFrame。 iFrame 可以引用如下文檔:

<!DOCTYPE html>
<html>
  <body>
    <script src="https://tryhackme.com/badge/170258"></script>
  </body>
</html>

只需將其添加到 React 即可按預期工作

<!DOCTYPE html>
<html>
  <head>
    <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>
    <script type="text/babel">
      ReactDOM.render(
        <div>
          <h1>React output before the iFrame</h1>
          <iframe src={"frame.html"} style={{"borderWidth":  0}}></iframe>
          <h1>React output after the IFrame</h1>
        </div>,
        document.getElementById('root')
      );
    </script>
  </body>
</html>

...產生輸出

結果

然而,當谷歌搜索一下 React 中的 iFrame 時,很容易遇到一些用例,在這種情況下,會出現阻止請求的不同類型的問題,在這種情況下,人們可能必須采取一些額外的措施來使 iFrame 正常運行。

總而言之,我認為這個用例有點不尋常,就我個人而言,我會嘗試以完全不同的方式解決它,但鑒於上下文就是這樣,這絕對是一種方法。

更新

為了避免使用為一個單獨的文件iframe中, srcDoc屬性可以在使用iframe讓你在線,而不是指定的內容,在這一點上,我們在抵達以下作用組件,而不是:

export default function App() {
  const iFrame = '<div><script src="https://tryhackme.com/badge/170258"></script></div>';

  return (
    <div>
      <h1>React output before the iFrame</h1>
      <iframe title={"badge"} srcDoc={iFrame} style={{ borderWidth: 0 }}>
      </iframe>
      <h1>React output after the IFrame</h1>
    </div>
  );
}

這個解決方案可以在這個沙箱中看到。 iframe元素添加更多樣式,使其根據需要融入。

最后,相應的單文件獨立解決方案(注意內容字符串傳遞所必需的轉義script結束標記):

<!DOCTYPE html>
<html>
  <head>
    <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>
    <script type="text/babel">

      const iFrame = `<div><script src="https://tryhackme.com/badge/170258"><\/script></div>`

      ReactDOM.render(
        <div>
          <h1>React output before the iFrame</h1>
          <iframe title={"badge"} srcDoc={iFrame} style={{"borderWidth":  0}}></iframe>
          <h1>React output after the IFrame</h1>
        </div>,
        document.getElementById('root')
      );
    </script>
  </body>
</html>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM