質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.40%

  • JavaScript

    21476questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • jQuery

    8546questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

外部ドメイン上のスクリプトのdocument.write処理の代替案について。

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 7,412

ikki57

score 276

 したいこと

- 外部ドメイン上に、document.writeでhtmlタグを記述しているスクリプトがある。(これは前提となります
- 上記を呼び出して、document.writeを実行し、タグ文字列を取得する。(それを任意の場所にappedする等、加工する)
- ただし、同期的に読み込むのではなく、非同期に読み込む必要がある。(これは前提となります

非同期に読み込んだ場合、下記エラーが発生する。

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.

http://so-zou.jp/web-app/tech/programming/javascript/dom/node/document/
に記載がある通り、
非同期で読み込まれる外部スクリプトからは、document.write()を実行できません。

上記をどうにかしたい。

 サンプルコード

 外部js
    document.writeln("<div id='additional'>here is additional dom</div>");

 html
下記、動作するケース

    <!DOCTYPE html>
    <html lang="ja">
    <head>
        <meta charaset="UTF-8">
        <title>document write by external domain script</title>
    </head>
    <body>
        <div class="wrapper">
            <h1>document write by external domain script</h1>
            <p>sample text. sample text. sample text. sample text. sample text. sample text.</p>
            <div id="target">
                here is target.
                <!-- これは動く -->
                <script src="http://example.com/js/script.js"></script>
            </div>
        </div>
    </body>
    </html>

下記、動作しないケース(先のエラーが発生する)
これを何かしらの方法で動作するようにしたい。

    <!DOCTYPE html>
    <html lang="ja">
    <head>
    <meta charaset="UTF-8">
    <title>document write by external domain script</title>
    </head>
    <body>
        <div class="wrapper">
            <h1>document write by external domain script</h1>
            <p>sample text. sample text. sample text. sample text. sample text. sample text.</p>
            <div id="target">
                here is target.
            </div>
        </div>

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
        <script>
            // # これはエラーになる
            $(function() {
                $('#target').after(
                    $("<script>").attr({src: "http://example.com/js/script.js"})
                );
            });
        </script>
    </body>
    </html>

よろしくお願い致します。
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • tozjp

    2015/11/04 18:53

    外部ソースを document.write ではない方法で書く事はできないという前提ですか?

    キャンセル

  • ikki57

    2015/11/04 18:55 編集

    tozjpさん

    ご連絡ありがとうござます。

    > 外部ソースを document.write ではない方法で書く事はできないという前提ですか?

    はい。
    **document.writeで記述されている外部ソースがある**、ということが前提となります。

    キャンセル

  • tozjp

    2015/11/04 18:57

    では、求めている挙動は何でしょうか。
    とりあえず汎用性があるように、外部リソースが write している文字列を値として取得できればどうとでもなりますかね。

    キャンセル

  • ikki57

    2015/11/04 19:09 編集

    そうですね、取得できれば何とかなるかと。
    (サンプルコードのエラーでは、取得すらできない状態なので、まずは取得する、が第一になります)

    詳細を申しますと、サンプルコードにあるように、
    外部リソースが write している文字列(htmlタグ)を取得し、
    そのhtmlタグを任意のDOMの後に連結したい(after)、が実装したいことになります。

    キャンセル

回答 2

checkベストアンサー

+3

$(function() {
    getWritten("script.js", function(html){
      $('#target').after(html);
    });
});
/**
 * ファイル名を与えた JS ファイル内で document.write() された文字列を取得して、コールバック関数に渡す。
 * @param {string} fileName *.js ファイル名
 * @param {Function} callback コールバック関数。第一引数に結果を受け取る。
 */
function getWritten(fileName, callback) {
  var $iframe = $("<iframe hidden\/>");
  // iframe が DOM 上に存在しないとうまくいかないので一時的に出力する
  $iframe.appendTo("body");
  var frameDocument = $iframe[0].contentWindow.document;
  var scriptTag = "<script src=\"" + fileName + "\"><\/script>";
  frameDocument.open();
  // frame 内での window.setResult に結果受信用関数を作成する
  $iframe[0].contentWindow.setResult = function(html) {
    // 親フレーム上から用済みの iframe を除去する
    $iframe.remove();
    // 取得した文字列には scriptTag が含まれているので削除してコールバックに渡す
    callback(html.replace(scriptTag, ""));
  };
  frameDocument.write(
    "<div id=\"area-to-write\">" +
    // div タグ内に scriptTag を貼る
    scriptTag +
    "<\/div>" +
    "<script>" +
    // div タグ内に出力された文字列を setResult() に渡す
    "setResult(document.querySelector(\"#area-to-write\").innerHTML);" +
    "<\/script>"
  );
  frameDocument.close();
}

iframe で同期的に読み込んで親フレームのコールバック関数を呼びます。
あらゆる場面でしっかり正常に動作するかはわかりませんが、足がかり程度にはなると思います。

特に外部ソースが document.write 以外の DOM 操作をしているとどうなるかわかりません。
また、グローバル変数は勝手に親フレームと共有されませんので使いたい値があるなら渡さなければいけません。

引数 fileName をエスケープしていないので必要そうなら書き換えてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/11/11 16:13

    tozjpさん

    返信遅くなって申し訳ありません。
    上記の件、現在確認中ですので、また追ってご連絡致します。
    とりいそぎ回答頂きましてありがとうございます。

    キャンセル

  • 2015/11/19 12:38 編集

    返信遅くなり申し訳ありません。
    頂いたコードにて要件を満たすことができ、また、ロジックの確認もできました。

    * iframeを生成、そのdoument内で対象の外部scriptをwriteし、実行させる
    ```
    <div id="area-to-write">
    <script src="http://example.com/js/script.js&quot;&gt;&lt;/script&gt;
    <div id="additional">here is additional dom!!!</div>
    </div>
    ```
    * 求める対象のDOMがwriteされる
    * 中身を取得する
    ````
    document.querySelector(\"#area-to-write\").innerHTML
    ```
    * 下記が取得される
    ```
    <script src="http://example.com/js/script.js&quot;&gt;&lt;/script&gt;
    <div id="additional">here is additional dom!!!</div>
    ```
    * 対象のDOMを取り出すための関数を、ともにwriteしておき実行させる(`setResult()`)
    * iframeを削除
    * scriptタグは削除する
    * callbackに渡し、callbackにて意図するDOMにappendする
    $('#target').after(html)


    iframeに関する理解が足りておらず、下記等を参考に頂いたコードを理解することができました。
    返信遅くなり、申し訳ありませんでした。

    参考)
    ▼IFRAME の内容を動的生成する正しい方法
    http://webos-goodies.jp/archives/51014876.html
    ▼ドキュメントに HTML 文字列を出力する, フレーム内にコンテンツを作成する(write() メソッドを使用)
    http://hakuhin.jp/js/iframe.html

    この度は誠にありがとうございました。
    今後ともどうぞよろしくお願い致します。

    キャンセル

  • 2015/11/19 21:18

    ここまで真剣に意図を汲んで頂けるとは!
    内容の方も何も補足すべきこともなく完璧なご理解だと思います。
    ご解決もできたようで、回答して良かったと思います。

    キャンセル

0

document.writeln = function(str){
  $('#target').after(str);
}
というのはどうでしょうか。
影響を確認しながら使わなければいけませんが、今どきdocument.writelnなんて他で使わないんじゃないかと。もし心配なら、
var docWrite = document.writeln;
//↑退避しておいて
document.writeln = function(str){
  $('#target').after(str);
}
//いろいろ処理して
//↓後で戻す
document.writeln = docWrite;
なんて書き方とかどうでしょう?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.40%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • JavaScript

    21476questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • jQuery

    8546questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。