HTML、CSSとJSコードをIframeに読み込む方法


あなたがちょうど答えのためにここにいるならば、物語でない.the solution is at the bottom .
jsfiddle、codepen、または他の人を使用した場合は、この問題はあなたに精通されます:目標はいくつかのHTML、CSS、およびJS(文字列として格納)を取って、内部にロードされたコードでiframeを作成することです.
この問題は簡単でなければならないが、それはそうではない.私がゴールデンチケットを見つけたまで、私はずっとずっと待っていた.
しかし、それ以降の詳細.それはもっと楽しいので、動作しなかったすべての物事から始めましょう.

を使用します。


少しの研究をした後に、私はAを加えることが可能であると発見するためにぞっとしましたsrcdoc iframeへの属性.
HTML文字列を渡すと、iframeはHTML内容の内部にロードされます.
<iframe srcdoc="<p>This text will appear in the iframe!</p>"></iframe>
残念ながら、このアプローチには2つの主な問題があります.

SRCDocのブラウザサポートは大きくない



IEまたはEDGEをサポートしたいなら、異なるアプローチ(またはポリフィル)を必要とします.

2 . CSS / JSから「エスケープ」することが可能です


srcdocを使った私の実装方法は次のようになります.
function setIframeContent(iframe, { html, css, js }) {
  const source = `
    <html>
      <head><style>${css}</style></head>
      <body>
        ${html}
        <script>${js}</script>
      </body>
    </html>
  `
  iframe.srcdoc = source
}
問題?CSSまたはJSを書くとき、HTMLランドに「エスケープ」することが可能です</style> or </script> を返します.
このバグは、実際にはかなり一般的ですjsfiddleとcodepenは影響を受けます.

リトルビッグプラネット


ブラウザのサポートの問題を修正するにはsrcdoc 正にsrc 属性.これを行うには、コードの代わりに本当のURLを渡す必要があります.
おそらく、HTML、CSS、およびJSの“get”パラメータを受け取り、以前と同じページのページを吐き出したページを設定することができますが、実際のURLからロードされます.
これはただ一つのことをする一つのエンドポイントが欲しいので、Serverlessなアーキテクチャを使用するのに絶好の時間です.私の試みです
module.exports = (req, res) => {
  // Code comes from GET params in URL
  const { html = '', css = '', js = '' } = req.query

  // Generate and send HTML page
  return res.send(`
    <html>
      <head><style>${css}</style></head>
      <body>
        ${html}
        <script>${js}</script>
      </body>
    </html>
  `)
}

これは事実上すべてのブラウザで動作しますが、独自の問題はありません.
  • CSS/jsからHTMLへの「エスケープ」はまだ問題です
  • ソースコード全体がURLで渡されます.isn't ideal .
  • リトルビッグプラネット™2でアップロード試みる


    我々の最初のブーメランはブラウザー支持問題を解決しました、しかし、対処するために「逃げている」問題がまだあります.
    幸いにも、我々はコードで渡す方法のため、これは実際に解決することができます.サーバー上のページにCSSとJSを挿入するのではなく、クライアントでそれを行うことができます!これは、URLの取得パラメータがクライアントのコンピュータにまだアクセスできるためです.
    ここでのソースは少し長いですが、これは動作します.
    module.exports = (req, res) => {
      return res.send(`
        <html>
          <head>
            <script type="text/javascript">
              window.addEventListener('load', function() {
                function getUrlParameter(name) {
                  name = name.replace(/[\\[]/, '\\\\[').replace(/[\\]]/, '\\\\]');
                  var regex = new RegExp('[\\\\?&]' + name + '=([^&#]*)');
                  var results = regex.exec(location.search);
                  return results === null ? '' : decodeURIComponent(results[1].replace(/\\+/g, ' '));
                };
    
                // Load JS from GET params (on client)
                var js = getUrlParameter('js');
                if (js) {
                  var script = document.createElement('script');
                  script.type = 'text/javascript';
                  script.text = js;
                  document.body.appendChild(script);
                }
    
                // Load CSS from GET params (on client)
                var css = getUrlParameter('css');
                if (css) {
                  var style = document.createElement('style');
                  style.type = 'text/css';
                  if (style.styleSheet) {
                    style.styleSheet.cssText = css;
                  } else {
                    style.appendChild(document.createTextNode(css));
                  }
                  document.head.appendChild(style);
                }
    
                // Remove the currently running script tag
                document.currentScript.parentNode.removeChild(document.currentScript);
              });
            </script>
          </head>
          <body>
            ${req.query.html || ''}
          </body>
        </html>
      `)
    }
    
    
    今、スクリプトまたはスタイルが怖いHTML文字を含んでいるなら、ブラウザはドキュメントにスクリプト/スタイルを挿入するとき、私たちのためにそれらを取り扱います.
    この解決策は.ファイン.これは、技術的に動作します.しかし、我々はまだ考慮する柔らかいURL長さ制限を持ちます.さらに、我々は現在、それがクライアントで起こるべきであるように感じる何かのサーバー側を扱っています.
    より良い方法があるに違いありません.

    BLOB URL


    この全体の時間は、URLからデータを読み込みます.
  • 最初にsrcdocを使ってURLから読み込む代わりにデータを読み込みます
  • その後、ブーメランを使用してURLからコードをロードしました
  • 次に、私たちのブーメランを1つのURLから来ているすべてのリソースにもかかわらず、「外部URLからのロードCSS/JS」をシミュレートしようとしました.
  • JavaScriptがこれをする機能を持っていることがわかります:Blob URL.

    ブロブ


    私たちはBlob 擬似ファイルを作成するコンストラクタ.ディスクからロードされた、あるいはURLからロードされた本物のファイルではない.しかし、多くの点で、それは実際のロードされたファイルと同じように機能します.
    では、私たちはURL.createObjectURL(blob) BLOBの内容を読み込むために使用するURLを作成します.
    以下に実際に動作する方法を示します.
    const getBlobURL = (code, type) => {
      const blob = new Blob([code], { type })
      return URL.createObjectURL(blob)
    }
    
    console.log(getBlobURL('<p>My webpage</p>', 'text/html'))
    // blob:https://dev.to/9ca05e31-05ea-48f8-838d-cc1ad0949ec8
    
    コンソールで上記のコードを実行してみてください.URLを記録します.新しいタブにURLをペーストする場合blob: 最初のビットは、HTMLを含むページを読み込みます.
    注意'text/html' 通過getBlobURL ? 我々もそれを変更することができます.CSSまたはJSブロブの生成は簡単ですtext/css or text/javascript それぞれ.
    Blob URLのもう一つの利点は、彼らが固執することです、そして、あなたが通常のURLにアクセスするどんな方法にでもアクセスすることができます.つまり、私たちは実際に別のURLからCSSとJSファイルを読み込むことができるので、“エスケープ”トリックはもはや問題ではないことを意味します.
    これを実際に実行するには以下のようにします.
    const getGeneratedPageURL = ({ html, css, js }) => {
      const getBlobURL = (code, type) => {
        const blob = new Blob([code], { type })
        return URL.createObjectURL(blob)
      }
    
      const cssURL = getBlobURL(css, 'text/css')
      const jsURL = getBlobURL(js, 'text/javascript')
    
      const source = `
        <html>
          <head>
            ${css && `<link rel="stylesheet" type="text/css" href="${cssURL}" />`}
            ${js && `<script src="${jsURL}"></script>`}
          </head>
          <body>
            ${html || ''}
          </body>
        </html>
      `
    
      return getBlobURL(source, 'text/html')
    }
    
    const url = getGeneratedPageURL({
      html: '<p>Hello, world!</p>',
      css: 'p { color: blue; }',
      js: 'console.log("hi")'
    })
    
    const iframe = document.querySelector('#iframe')
    iframe.src = url
    
    そして、BLOB URLに対するブラウザのサポートはsrcdocよりずっと良いです;

    道徳的?


    言語と戦うな.
    私は何をしたいか知りました:URLからデータをロードしてください.それはちょうど私にそれを行うには、非多彩な方法を探すために発生しました!