0

コンポーネントが4つのJSファイルに分割されたレガシーJavaScriptアプリケーションを維持しています。

「Default.aspx」、「set1.aspx」、「set2.aspx」、「set3.aspx」です。ASPX ページは、それぞれのセットに属する複数の (まったく異なる) ソース ファイルから圧縮された JS を書き出し、コンテンツ タイプ ヘッダーを "text/javascript" に設定します。

アプリケーションは、最初のセットへの参照を追加し、メイン エントリ オブジェクトを作成することによって呼び出されます。

<script src="/app/default.aspx" type="text/javascript"></script>

<script type="text/javascript>

    var ax;  

    // <body onload="OnLoad()">
    function OnLoad() {
        ax = new MyApp(document.getElementById("axTargetDiv"));
    }

</script>

スクリプトの最初のセット (default.aspx) の最後には、次の正確なコードがあります。

function Script(src) {
    document.write('<script src="' + src + '" type="text/javascript"></script>');
}

Script("set1.aspx?v=" + Settings.Version);

これにより、2 番目のスクリプト セット (set1.aspx) が読み込まれます。そして、これはすべての主要なブラウザー (IE6-8 Firefox Safari Opera Chrome) でエラーなしで動作します。

ただし、私は静かにこのスクリプトに取り組んでいるので、多くの場所で関数呼び出しを単純化し、上記のスクリプト関数を誤ってインライン化して、次のコードを作成したいと考えています。

document.write('<script src="set1.aspx?v=' + Settings.Version + '" type="text/javascript"></script>');

テストページでテストすると、すべてのブラウザーで次のエラーがスローされるようになりました。

MyApp is not defined.

これは次の行で発生します: ax = new MyApp(...as Visual Studio JS debugger and Firebug report it.

この質問に投稿された最初の4つの回答でさまざまな方法を試しましたが、役に立ちませんでした。MyApp を正常にロードできるようにする唯一の方法は、実際の「スクリプトの追加」コードを関数 (つまりdocument.write('script')行) 内に配置することだけです。

関数内に行を入れるとdocument.write機能しますが、そうでない場合は機能しません。何が起こっていますか?

スクリプト テキストの分割および/またはエスケープは機能しません。

4

4 に答える 4

4

問題を確認するには、スクリプト要素の一番上の行を見てください。

<script type="text/javascript">
    document.write('<script src="set1.aspx?v=1234" type="text/javascript"></script>');
</script>

そのため、HTML パーサーが現れて、開始の <script> タグを認識します。<script> 内では、通常の <tag> 解析は無効になっています (SGML 用語では、要素には CDATA コンテンツがあります)。スクリプト ブロックの終了位置を見つけるために、HTML パーサーは一致する終了タグ </script> を探します。

最初に見つかったものは、文字列リテラル内のものです。HTML パーサーはそれが文字列リテラルの中にあることを認識できません。HTML パーサーは JavaScript 構文について何も知らず、CDATA しか認識していないためです。つまり、あなたが実際に言っていることは次のとおりです。

<script type="text/javascript">
    document.write('<script src="set1.aspx?v=1234" type="text/javascript">
</script>

つまり、閉じられていない文字列リテラルと未完了の関数呼び出しです。これにより JavaScript エラーが発生し、目的のスクリプト タグが書き込まれません。

問題を解決するための一般的な試みは次のとおりです。

document.write('...</scr' + 'ipt>');

これはまだ技術的に間違っています (検証されません)。これは、SGML では、CDATA 要素を終了する文字シーケンスが実際には '</tagname>' ではなく、単に '</' であるためです。このシーケンスは、上記の行にまだ存在しています。ブラウザーは一般的により寛容であり、実際にはそれを許可します。

おそらく最善の解決策は、シーケンスをエスケープすることです。いくつかの可能性がありますが、最も簡単なのは JavaScript 文字列リテラル エスケープ ('\xNN') を使用することです。

document.write('\x3Cscript src="set1.aspx?v=1234\x26w=5678" type="text/javascript"\x3E\x3C/script\x3E');

上記はすべての「<」、「>」をエスケープします および「&」これにより、'</' シーケンスが文字列に表示されるのを防ぐだけでなく、エラーを発生させずに XHTML スクリプト ブロックに挿入することもできます。

(XHTML には CDATA 要素のようなものはないため、これらの文字は通常のコンテンツに含まれている場合と同じ意味を持ち、スクリプト ブロック内の文字列 '<script>' は実際にはネストされたスクリプト要素を作成します! <![CDATA[ セクションを使用して XHTML スクリプト ブロックで <>& を許可するには、これは少し見苦しく、インライン スクリプトでこれらの文字を使用することは通常避けたほうがよいでしょう。)

于 2009-04-08T08:41:18.253 に答える
1

あなたも試すことができます:

var script = document.createElement("script");
script.src = "set1.aspx?v=1234";
script.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(script);

スティーブ

于 2009-04-08T08:30:36.687 に答える
1

1) スクリプトが「実際に」ページに含まれる前に MyApp を参照しようとしないでください。

2) インライン ローダーで「スクリプト」という単語を次のように分割してみてください。

<script type="text/javascript">
document.write('<scr' + 'ipt src="set1.aspx?v=1234" type="text/javascript"></scr' + 'ipt>');
</script>

または、Google アナリティクス コードから借用し、正常に使用できた次の構文を使用します。

<script type="text/javascript">
document.write(unescape("%3Cscript src='set1.aspx?v=1234' type='text/javascript'%3E%3C/script%3E"));
</script>
于 2009-04-08T06:17:42.497 に答える
0

JQuery を使用できる場合は、次を使用できます。

$.getScript("set1.aspx?v=1234");

これにより、スクリプトがグローバル JavaScript コンテキストにロードされます。応答の contenttype を「text/javascript」に設定してください。

お役に立てれば...

于 2009-04-08T07:52:38.290 に答える