39

私は次のようなHTMLのチャンクを返すAJAX呼び出しを行っているWebページで作業しています。

<div>
  <!-- some html -->
  <script type="text/javascript">
    /** some javascript */
  </script>
</div>

すべてをDOMに挿入していますが、JavaScriptが実行されていません。それを実行する方法はありますか?

詳細:スクリプトブロックの内容を制御することはできません(したがって、呼び出すことができる関数に変更することはできません)。ブロック全体を実行する必要があります。JavaScriptはHTMLのより大きなブロック内にあるため、応答でevalを呼び出すことはできません。ある種の正規表現を実行してJavaScriptを分離し、それに対してevalを呼び出すこともできますが、それはかなり厄介です。誰かがより良い方法を知っていますか?

4

7 に答える 7

18

要素の innerHTML プロパティを設定して追加されたスクリプトは実行されません。新しい div を作成し、その innerHTML を設定してから、この新しい div を DOM に追加してみてください。例えば:

<html>
<頭>
<script type='text/javascript'>
関数 addScript()
{
    var str = "<script>alert('私はここにいます');<\/script>";
    var newdiv = document.createElement('div');
    newdiv.innerHTML = str;
    document.getElementById('target').appendChild(newdiv);
}
</script>
</head>
<本体>
<input type="button" value="add script" onclick="addScript()"/>
<div>ハローワールド</div>
<div id="ターゲット"></div>
</body>
</html>
于 2008-09-16T19:38:57.847 に答える
15

応答を使用して div などを埋める場合は、正規表現を使用する必要はありません。getElementsByTagName を使用できます。

div.innerHTML = response;
var scripts = div.getElementsByTagName('script');
for (var ix = 0; ix < scripts.length; ix++) {
    eval(scripts[ix].text);
}
于 2008-09-16T19:27:41.633 に答える
9

@Edからの受け入れられた回答。Firefox、Google Chrome、または Safari ブラウザーの現在のバージョンでは動作しません。動的に追加されたスクリプトを呼び出すために、彼の例をうまく使いこなすことができました。

必要な変更は、スクリプトを DOM に追加する方法のみです。トリックとして追加する代わりにinnerHTML、新しいスクリプト要素を作成innerHTMLし、作成された要素に実際のスクリプトコンテンツを追加してから、スクリプト要素を実際のターゲットに追加しました。

<html>
<head>
<script type='text/javascript'>
function addScript()
{
    var newdiv = document.createElement('div');

    var p = document.createElement('p');
    p.innerHTML = "Dynamically added text";
    newdiv.appendChild(p);

    var script = document.createElement('script');
    script.innerHTML = "alert('i am here');";
    newdiv.appendChild(script);

    document.getElementById('target').appendChild(newdiv);
}
</script>
</head>
<body>
<input type="button" value="add script" onclick="addScript()"/>
<div>hello world</div>
<div id="target"></div>
</body>
</html>

これは、Firefox 42、Google Chrome 48、および Safari 9.0.3 で機能します。

于 2016-02-17T16:37:34.177 に答える
2

別の方法として、InnerHTML を使用して Ajax 呼び出しからの戻り値を DOM にダンプするだけではありません。

各ノードを動的に挿入すると、スクリプトが実行されます。

そうしないと、ブラウザーはテキスト ノードを挿入していると見なし、スクリプトを無視します。

Eval の使用は、Javascript VM の別のインスタンスを起動し、渡された文字列を JIT する必要があるため、かなり悪質です。

于 2008-09-16T19:36:13.877 に答える
1

おそらく最善の方法は、スクリプト ブロックの内容を DOM 経由で直接識別して評価することです。

ただし、注意が必要です。オフサイト呼び出しの制限を克服するためにこれを実装している場合、セキュリティ ホールが開いています。

実装するものは何でも XSS に悪用される可能性があります。

于 2008-09-16T19:33:38.750 に答える
0

これをネイティブで行う一般的な Ajax ライブラリの 1 つを使用できます。プロトタイプが好きです。Ajax 呼び出しの一部として evalScripts:true を追加するだけで、自動的に実行されます。

于 2008-09-16T20:09:02.550 に答える
0

危険な生活が好きな人向け:

// This is the HTML with script element(s) we want to inject
var newHtml = '<b>After!</b>\r\n<' +
  'script>\r\nchangeColorEverySecond();\r\n</' +
  'script>';
  
// Here, we separate the script tags from the non-script HTML
var parts = separateScriptElementsFromHtml(newHtml);

function separateScriptElementsFromHtml(fullHtmlString) {
    var inner = [], outer = [], m;
    while (m = /<script>([^<]*)<\/script>/gi.exec(fullHtmlString)) {
        outer.push(fullHtmlString.substr(0, m.index));
        inner.push(m[1]);
        fullHtmlString = fullHtmlString.substr(m.index + m[0].length);
    }
    outer.push(fullHtmlString);
    return {
        html: outer.join('\r\n'),
        js: inner.join('\r\n')
    };
}

// In 2 seconds, inject the new HTML, and run the JS
setTimeout(function(){
  document.getElementsByTagName('P')[0].innerHTML = parts.html;
  eval(parts.js);
}, 2000);


// This is the function inside the script tag
function changeColorEverySecond() {
  document.getElementsByTagName('p')[0].style.color = getRandomColor();
  setTimeout(changeColorEverySecond, 1000);
}

// Here is a fun fun function copied from:
// https://stackoverflow.com/a/1484514/2413712
function getRandomColor() {
  var letters = '0123456789ABCDEF';
  var color = '#';
  for (var i = 0; i < 6; i++) {
    color += letters[Math.floor(Math.random() * 16)];
  }
  return color;
}
<p>Before</p>

于 2020-08-31T20:04:14.077 に答える