Ausführen von <script>, das von innerHTML nach dem AJAX-Aufruf injiziert wurde

99

Es gibt eine Div namens "Content":

<div id="content"></div>

Es sollte mit Daten aus einer PHP-Datei von AJAX gefüllt sein, einschließlich eines <script>Tags. Das Skript in diesem Tag wird jedoch nicht ausgeführt.

<div id="content"><!-- After AJAX loads the stuff that goes here -->
   <script type="text/javascript">
     //code
   </script>
   <!-- More stuff that DOES work here -->
</div>
JCOC611
quelle
Wie lädst du das Div? Abhängig von der verwendeten Bibliothek können Sie normalerweise steuern, ob Sie die Skripte nur nach dem Laden von Ajax ausführen möchten.
Bill Yang
1
Nachdem window.onloadich ein XMTHttpRequestObjekt erstellt habe, um eine andere (PHP-) Seite anzufordern, die den Inhalt des Div enthält, einschließlich eines Skripts. Ich mache das mit einfachem JS, keine Bibliotheken (außer meinem eigenen lol)
JCOC611

Antworten:

65

Als DOM-Text eingefügtes JavaScript wird nicht ausgeführt. Sie können jedoch das dynamische Skriptmuster verwenden , um Ihr Ziel zu erreichen. Die Grundidee besteht darin, das Skript, das Sie ausführen möchten, in eine externe Datei zu verschieben und ein Skript-Tag zu erstellen, wenn Sie Ihre Ajax-Antwort erhalten. Anschließend legen Sie das srcAttribut Ihres Skript-Tags fest und voila lädt das externe Skript und führt es aus.

Dieser andere StackOverflow-Beitrag kann auch für Sie hilfreich sein: Können Skripte mit innerHTML eingefügt werden? .

Chocula
quelle
Sie können alle geladenen Skripte auswählen und mit der Funktion eval () ausführen:$('#audit-view script').each(function (index, element) { eval(element.innerHTML); })
Jerzy Gebler
Javascript, das der Seite hinzugefügt wurde, sollte unbedingt ausgeführt werden. ( jsfiddle.net/wnn5fz3m/1 zum Beispiel). Die Frage ist, warum es nicht manchmal?
NoBugs
@Chocula Ich habe mein Skript in eine separate Datei verschoben, aber es funktioniert nicht teilweise. Können Sie mir dabei helfen? stackoverflow.com/questions/42941856/…
Samra
Zu Ihrer Information (@NoBugs gibt mir einen Hinweis). Ich habe versucht, einfach javascirpt element.innerHTML = zzz und desnt Arbeit. Dann versuche ich Jquery $ (Element) .html (zzz) und habe gearbeitet.
Gtryonp
66

Ich habe diesen Code verwendet, er funktioniert einwandfrei

var arr = MyDiv.getElementsByTagName('script')
for (var n = 0; n < arr.length; n++)
    eval(arr[n].innerHTML)//run script inside div
Firas Nizam
quelle
4
Wenn Sie mich fragen, ist dies eine weitaus bessere Antwort als die akzeptierte. Dies ist so ziemlich JavaScript-Injektion.
Xedret
Dies ist zwar nützlich, beantwortet aber nicht die Frage, warum Skripte nicht ausgeführt werden. Siehe zum Beispiel jsfiddle.net/fkqmcaz7 und jsfiddle.net/wnn5fz3m/1. Es sollte unbedingt ausgeführt werden, und ich finde keinen vereinfachten Fall, in dem es nicht funktioniert.
NoBugs
1
@NaoiseGolden OP fragt buchstäblich nach der Skriptausführung, daher denke ich, dass es hier in Ordnung ist. :-)
Tag dreht sich
1
Eval () wird nicht dringend empfohlen. Siehe dies - stackoverflow.com/questions/9107847/…
Kings
15

Wenn Sie einen Skriptblock in Ihr div über Ajax wie folgt laden:

<div id="content">
    <script type="text/javascript">
    function myFunction() {
      //do something
    }
    myFunction();
    </script>
</div>

... es aktualisiert einfach das DOM Ihrer Seite, myFunction () wird nicht unbedingt aufgerufen.

Sie können eine Ajax-Rückrufmethode wie die in der ajax () -Methode von jQuery verwenden, um zu definieren, was ausgeführt werden soll, wenn die Anforderung abgeschlossen ist.

Was Sie tun, unterscheidet sich vom Laden einer Seite mit JavaScript von Anfang an (das ausgeführt wird).

Ein Beispiel für die Verwendung des Erfolgs- und Fehlerrückrufs nach dem Abrufen von Inhalten:

  $.ajax({
    type: 'GET',
    url: 'response.php',
    timeout: 2000,
    success: function(data) {
      $("#content").html(data);
      myFunction();
    },
    error: function (XMLHttpRequest, textStatus, errorThrown) {
      alert("error retrieving content");
    }

Eine andere schnelle und schmutzige Möglichkeit besteht darin, mit eval () Skriptcode auszuführen, den Sie als DOM-Text eingefügt haben, wenn Sie jQuery oder eine andere Bibliothek nicht verwenden möchten.

Christopher Tokar
quelle
Wie kann ich mithilfe des Rückrufs von jQuery den Code im neuen <script> "ausführen"?
JCOC611
Ich habe ein Beispiel für die Verwendung des Erfolgsrückrufs hinzugefügt:
Christopher Tokar
1
Ich danke dir sehr! die "myFunction ();" Teil war, was ich aus meinem Code herausließ.
Jason
11

Hier ist das Skript, das alle Skript-Tags im Text auswertet.

function evalJSFromHtml(html) {
  var newElement = document.createElement('div');
  newElement.innerHTML = html;

  var scripts = newElement.getElementsByTagName("script");
  for (var i = 0; i < scripts.length; ++i) {
    var script = scripts[i];
    eval(script.innerHTML);
  }
}

Rufen Sie diese Funktion einfach auf, nachdem Sie Ihren HTML-Code vom Server erhalten haben. Seien Sie gewarnt: miteval kann gefährlich sein.

Demo: http://plnkr.co/edit/LA7OPkRfAtgOhwcAnLrl?p=preview

Evgenii
quelle
5

Dies funktioniert bei mir mit jQuery, sofern Sie nicht versuchen, eine Teilmenge des von XHR zurückgegebenen HTML-Codes an das Dokument anzuhängen. (Siehe diesen Fehlerbericht, der das Problem mit jQuery zeigt.)

Hier ist ein Beispiel, das zeigt, wie es funktioniert:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 
<html lang="en"> 
<head> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
    <title>test_1.4</title> 
    <script type="text/javascript" charset="utf-8" src="jquery.1.4.2.js"></script> 
    <script type="text/javascript" charset="utf-8"> 
        var snippet = "<div><span id='a'>JS did not run<\/span><script type='text/javascript'>" +
        "$('#a').html('Hooray! JS ran!');" +
        "<\/script><\/div>";
        $(function(){
            $('#replaceable').replaceWith($(snippet));
        });
    </script> 
</head> 
<body> 
    <div id="replaceable">I'm going away.</div> 
</body> 
</html>

Hier ist das Äquivalent zu den oben genannten: http://jsfiddle.net/2CTLH/

Phrogz
quelle
1
Es ist höchst unwahrscheinlich, dass dies derzeit die Lösung für das Problem ist, da dies ein Fehler mit einer wirklich alten Version von jQuery war.
NoBugs
3

Hier ist eine Funktion, mit der Sie AJAX-Antworten analysieren können, insbesondere wenn Sie minifiedjs verwenden und das zurückgegebene Javascript ausführen möchten oder nur die Skripte analysieren möchten, ohne sie dem DOM hinzuzufügen. Sie behandelt auch Ausnahmefehler. Ich habe diesen Code in der php4sack-Bibliothek verwendet und er ist außerhalb der Bibliothek nützlich.

function parseScript(_source) {
    var source = _source;
    var scripts = new Array();

    // Strip out tags
    while(source.toLowerCase().indexOf("<script") > -1 || source.toLowerCase().indexOf("</script") > -1) {
        var s = source.toLowerCase().indexOf("<script");
        var s_e = source.indexOf(">", s);
        var e = source.toLowerCase().indexOf("</script", s);
        var e_e = source.indexOf(">", e);

        // Add to scripts array
        scripts.push(source.substring(s_e+1, e));
        // Strip from source
        source = source.substring(0, s) + source.substring(e_e+1);
    }

    // Loop through every script collected and eval it
    for(var i=0; i<scripts.length; i++) {
        try {
          if (scripts[i] != '')
          {         
            try  {          //IE
                  execScript(scripts[i]);   
      }
      catch(ex)           //Firefox
      {
        window.eval(scripts[i]);
      }   

            }  
        }
        catch(e) {
            // do what you want here when a script fails
         // window.alert('Script failed to run - '+scripts[i]);
          if (e instanceof SyntaxError) console.log (e.message+' - '+scripts[i]);
                    }
    }
// Return the cleaned source
    return source;
 }
Andre Van Zuydam
quelle
2

Wenn Sie etwas einfügen, für das das Skript-Tag erforderlich ist, wird möglicherweise ein nicht erfasster Syntaxfehler angezeigt, und es wird ein unzulässiges Token angezeigt . Um dies zu vermeiden, müssen Sie die Schrägstriche in Ihren schließenden Skript-Tags vermeiden. dh;

var output += '<\/script>';

Gleiches gilt für alle schließenden Tags, z. B. ein Formular-Tag.

TommyRay
quelle
0

Ich hatte hier einen ähnlichen Beitrag, addEventListener load on ajax load WITHOUT jquery

Wie ich es gelöst habe, war das Einfügen von Aufrufen von Funktionen in meine stateChange-Funktion. Die Seite, die ich eingerichtet hatte, bestand aus 3 Schaltflächen, mit denen 3 verschiedene Seiten in die contentArea geladen wurden. Da ich wissen musste, welche Schaltfläche gedrückt wurde, um Seite 1, 2 oder 3 zu laden, konnte ich leicht if / else-Anweisungen verwenden, um zu bestimmen, welche Seite geladen wird und welche Funktion dann ausgeführt werden soll. Ich habe versucht, verschiedene Button-Listener zu registrieren, die nur funktionieren würden, wenn die bestimmte Seite aufgrund von Element-IDs geladen wurde.

so...

Wenn (Seite1 geladen wird, pageload = 1), führen Sie die Funktion registerListeners1 aus

dann das gleiche für Seite 2 oder 3.

Richard Chase
quelle
0

Dies funktionierte für mich, indem eval für jeden Skriptinhalt von ajax .done aufgerufen wurde:

$.ajax({}).done(function (data) {      
    $('div#content script').each(function (index, element) { eval(element.innerHTML); 
})  

Hinweis: Ich habe keine Parameter in $ .ajax geschrieben, die Sie entsprechend Ihrem Ajax anpassen müssen.

shivgre
quelle
0

Mein Fazit ist, dass HTML keine NESTED SCRIPT-Tags zulässt. Wenn Sie Javascript zum Einfügen von HTML-Code verwenden, der Skript-Tags enthält, funktioniert dies nicht, da das Javascript auch in einem Skript-Tag enthalten ist. Sie können es mit dem nächsten Code testen und Sie werden feststellen, dass es nicht funktionieren wird. Der Anwendungsfall ist, dass Sie einen Dienst mit AJAX oder ähnlichem aufrufen, HTML erhalten und es direkt in das HTML-DOM einfügen möchten. Wenn der injizierte HTML-Code in SCRIPT-Tags enthalten ist, funktioniert dies nicht.

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"></head><body></body><script>document.getElementsByTagName("body")[0].innerHTML = "<script>console.log('hi there')</script>\n<div>hello world</div>\n"</script></html>
Antonio Martin
quelle
-3

Sie können die Seite auch mit einem Skript wie dem folgenden laden:

<div id="content" onmouseover='myFunction();$(this).prop( 'onmouseover', null );'>
<script type="text/javascript">
function myFunction() {
  //do something
}
myFunction();
</script>
</div>

Dadurch wird die Seite geladen, das Skript ausgeführt und der Ereignishandler entfernt, wenn die Funktion ausgeführt wurde. Dies wird nicht sofort nach dem Laden von Ajax ausgeführt. Wenn Sie jedoch darauf warten, dass der Benutzer das div-Element eingibt, funktioniert dies einwandfrei.

PS. Benötigt Jquery

Joshua Klein
quelle