<Script> -Element kann nicht angehängt werden

276

Irgendeine Idee, warum der folgende Code das Skriptelement nicht zum DOM hinzufügt?

var code = "<script></script>";
$("#someElement").append(code);
Dan Burzo
quelle
4
Definieren Sie "funktioniert nicht" - obwohl ich vermute, dass das Problem darin besteht, dass Skripte nicht wirklich Teil des Dom-Baums sind.
Joel Coehoorn
1
Ich wette, dass der Skriptknoten zum DOM hinzugefügt wird, der Browser das Skript jedoch nicht ausführt.
Outlaw Programmer
Dan, wie hast du das eigentlich getestet?
James
1
@Joel - "funktioniert nicht" = es hat keine Auswirkung, dh der Code im Skript wird nicht ausgeführt @Outlaw Programmer - der Knoten wird nicht zum DOM hinzugefügt @Jimmy Ja, ich habe ihn getestet und er funktioniert nicht
Dan Burzo

Antworten:

259

Ich habe Probleme gesehen, bei denen einige Browser einige Änderungen nicht berücksichtigen, wenn Sie sie direkt ausführen (was bedeutet, dass Sie den HTML-Code aus Text erstellen, wie Sie es mit dem Skript-Tag versuchen), aber wenn Sie sie mit integrierten Befehlen ausführen Dinge laufen besser. Versuche dies:

var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.src = url;
$("#someElement").append( script );

Von: JSON für jQuery

Akrosman
quelle
18
Das <script> -Tag muss dem DOM selbst hinzugefügt werden, nicht dem innerHTML eines vorhandenen Elements.
Diodeus - James MacFarlane
6
@Diodeus das innerHTML ist Teil des DOM und wird vom Browser im laufenden Betrieb analysiert. Dies ist also ein gültiger Fall.
Cristian Toma
5
Verwenden Sie nicht nur das Anhängen von jQuery, wenn das Element wirklich im DOM angezeigt werden soll. Verwenden Sie dazu das native appendChild.
Minqi Pan
8
$("#someElement")[0].appendChild( script );
Minqi Pan
352

Die gute Nachricht ist:

Es funktioniert zu 100%.

Fügen Sie einfach etwas in das Skript-Tag ein, z alert('voila!');. Die richtige Frage, die Sie vielleicht stellen möchten: "Warum habe ich sie nicht im DOM gesehen?".

Karl Swedberg hat den Kommentar des Besuchers auf der jQuery-API-Site gut erklärt . Ich nicht möchte alle seine Worte wiederholen, können Sie direkt lesen es hier (ich fand es schwer zu navigieren durch die Kommentare dort) .

Alle Einfügemethoden von jQuery verwenden intern eine domManip-Funktion, um Elemente vor und nach dem Einfügen in das DOM zu bereinigen / zu verarbeiten. Die domManip-Funktion zieht unter anderem alle einzufügenden Skriptelemente heraus und führt sie durch eine "evalScript-Routine", anstatt sie mit dem Rest des DOM-Fragments zu injizieren. Es fügt die Skripte separat ein, wertet sie aus und entfernt sie dann aus dem DOM.

Ich glaube, dass einer der Gründe, warum jQuery dies tut, darin besteht, Fehler zu vermeiden, die unter bestimmten Umständen beim Einfügen von Skripten in Internet Explorer auftreten können. Außerdem wird vermieden, dass dasselbe Skript wiederholt eingefügt / ausgewertet wird (was möglicherweise zu Problemen führen kann), wenn es sich in einem enthaltenden Element befindet, das Sie einfügen und dann im DOM verschieben.

Als nächstes fasse ich die schlechten Nachrichten zusammen, indem ich mithilfe der .append()Funktion ein Skript hinzufüge.


Und die schlechte Nachricht ist ..

Sie können Ihren Code nicht debuggen.

Ich scherze nicht, selbst wenn Sie ein debugger;Schlüsselwort zwischen der Zeile hinzufügen, die Sie als Haltepunkt festlegen möchten, erhalten Sie am Ende nur den Aufrufstapel des Objekts, ohne den Haltepunkt im Quellcode zu sehen (ganz zu schweigen davon, dass dies der Fall ist Das Schlüsselwort funktioniert nur im Webkit-Browser. Alle anderen gängigen Browser scheinen dieses Schlüsselwort wegzulassen .

Wenn Sie vollständig verstehen, was Ihr Code tut, ist dies ein kleiner Nachteil. Wenn Sie dies nicht tun, werden Sie debugger;überall ein Schlüsselwort hinzufügen , um herauszufinden, was mit Ihrem (oder meinem) Code nicht stimmt. Wie auch immer, es gibt eine Alternative. Vergessen Sie nicht, dass Javascript HTML-DOM nativ manipulieren kann.


Problemumgehung.

Verwenden Sie Javascript (nicht jQuery), um HTML-DOM zu bearbeiten

Wenn Sie die Debugging-Fähigkeit nicht verlieren möchten, können Sie die native HTML-DOM-Manipulation mit Javascript verwenden. Betrachten Sie dieses Beispiel:

var script   = document.createElement("script");
script.type  = "text/javascript";
script.src   = "path/to/your/javascript.js";    // use this for linked script
script.text  = "alert('voila!');"               // use this for inline script
document.body.appendChild(script);

Da ist es, genau wie früher, nicht wahr? Und vergessen Sie nicht, alle Objekte, auf die verwiesen wird und die nicht mehr benötigt werden, um Speicherlecks zu vermeiden, im DOM oder im Speicher zu bereinigen. Sie können diesen Code zum Aufräumen verwenden:

document.body.removechild(document.body.lastChild);
delete UnusedReferencedObjects; // replace UnusedReferencedObject with any object you created in the script you load.

Der Nachteil dieser Problemumgehung besteht darin, dass Sie möglicherweise versehentlich ein doppeltes Skript hinzufügen, und das ist schlecht. Von hier aus können Sie die .append()Funktion leicht nachahmen , indem Sie vor dem Hinzufügen eine Objektüberprüfung hinzufügen und das Skript direkt nach dem Hinzufügen aus dem DOM entfernen. Betrachten Sie dieses Beispiel:

function AddScript(url, object){
    if (object != null){
        // add script
        var script   = document.createElement("script");
        script.type  = "text/javascript";
        script.src   = "path/to/your/javascript.js";
        document.body.appendChild(script);

        // remove from the dom
        document.body.removeChild(document.body.lastChild);
        return true;
    } else {
        return false;
    };
};

function DeleteObject(UnusedReferencedObjects) {
    delete UnusedReferencedObjects;
}

Auf diese Weise können Sie ein Skript mit Debugging-Funktion hinzufügen, ohne sich vor Skriptduplizitäten zu schützen. Dies ist nur ein Prototyp, den Sie für alles erweitern können, was Sie möchten. Ich habe diesen Ansatz verwendet und bin damit sehr zufrieden. Sicher genug, ich werde niemals jQuery verwenden.append() , um ein Skript hinzuzufügen.

Hendra Uzia
quelle
2
Tolle Erklärung, danke! Aber war "UnusedReferencedObjects"?
Acme
Vielen Dank. Ich nehme an, Sie haben sich auf das erste Auftreten von "UnusedReferencedObjects" bezogen, bei dem es sich vermutlich um ein Objekt handelt, das Sie in dem von Ihnen geladenen Skript erstellt haben. Ich denke, Sie verstehen besser, wenn Sie sehen, was die DeleteObject-Funktion tut. Sie löscht einfach jedes Objekt, das Sie an die Funktion übergeben haben. Ich werde einen Kommentar in den Code einfügen, um klar zu sein. :)
Hendra Uzia
Super Post! Das Beispiel von aCrosman hat bei mir nicht funktioniert und nachdem ich Ihren Beitrag fertiggestellt habe, habe ich $ ("# someElement") ersetzt. Append (script); mit $ ("# someElement") [0] .appendChild (Skript); Was es behoben hat :) Danke für die Explantation
Maarten Kieft
7
$.getScriptist in jQuery integriert.
zzzzBov
SourceURLs ( blog.getfirebug.com/2009/08/11/… ) können beim Debuggen helfen.
Vsevik
23

Mit der Funktion jQuery kann eine JavaScript-Datei dynamisch geladen werdengetScript

$ .getScript ('http://www.whatever.com/shareprice/shareprice.js', function () {
  Display.sharePrice ();
});

Jetzt wird das externe Skript aufgerufen, und wenn es nicht geladen werden kann, wird es ordnungsgemäß beeinträchtigt.

Spielball
quelle
7
Dadurch wird nichts in das DOM eingefügt. Es ruft eval().
nh2
20

Was meinst du mit "nicht arbeiten"?

jQuery erkennt, dass Sie versuchen, ein SCRIPT-Element zu erstellen, und führt den Inhalt des Elements automatisch im globalen Kontext aus. Erzählst du mir, dass das bei dir nicht funktioniert? - -

$('#someElement').append('<script>alert("WORKING");</script>');

Bearbeiten: Wenn Sie das SCRIPT-Element nicht im DOM sehen (z. B. in Firebug), nachdem Sie den Befehl ausgeführt haben, wird jQuery, wie gesagt, den Code ausführen und dann das SCRIPT-Element löschen - ich glaube, dass SCRIPT-Elemente werden immer an den Körper angehängt ... aber trotzdem - die Platzierung hat in dieser Situation absolut keinen Einfluss auf die Codeausführung.

James
quelle
17

Das funktioniert:

$('body').append($("<script>alert('Hi!');<\/script>")[0]);

Es scheint, als ob jQuery mit Skripten etwas Kluges macht, sodass Sie das HTML-Element anstelle des jQuery-Objekts anhängen müssen.

Darwin
quelle
2
Dies ist die einzige Lösung, die in meinem Fall funktioniert. Die anderen oben genannten Lösungen hängen vom Javascript-Code ab, der vorab in der HTML-Datei vorhanden ist. Da ich Code dynamisch hinzufüge, kann ein solcher Javascript-Code nicht im Voraus erkannt werden! DANKE Darwin !!
Tgoneil
14

Versuchen Sie dies kann hilfreich sein:

var fileref=document.createElement('script');
fileref.setAttribute("type","text/javascript");
fileref.setAttribute("src","scriptAnalytics.js");
document.getElementsByTagName("head")[0].appendChild(fileref);
Jainul Khan
quelle
9
Keine Ahnung, warum dieser Negativ-Typ der einzige ist, der nicht dumm genug ist, JQuery für alles zu verwenden!
SSpoke
Wahrscheinlich verwenden die meisten Antworten jQuery, da das OP in der Frage jQuery verwendet.
Sanbor
3

Ich möchte das Gleiche tun, aber ein Skript-Tag in einem anderen Frame anhängen!

var url = 'library.js'; 
var script = window.parent.frames[1].document.createElement('script' ); 
script.type = 'text/javascript'; 
script.src = url;
$('head',window.parent.frames[1].document).append(script);
Julio
quelle
3
<script>
    ...
    ...jQuery("<script></script>")...
    ...
</script>

Das </script>Literal innerhalb des Strings beendet das gesamte Skript, um zu vermeiden, "</scr" + "ipt>"dass es stattdessen verwendet werden kann.

Roman Odaisky
quelle
Oder binden Sie Ihr Javascript nicht direkt in das HTML-Dokument ein. Externe Skriptdateien haben dieses Problem nicht.
Ian Clelland
Escape-Sequenzen : "\x3cscript\x3e\x3c/script\x3e". In XHTML müssen Sie nur einen auskommentierten CDATA-Block einfügen.
Eli Gray
2
Es ist eher das </, was nicht erlaubt ist. Siehe stackoverflow.com/questions/236073/…
Gumbo
2

Das Hinzufügen der Quell-URL zur Skriptdatei hat geholfen, wie auf dieser Seite erwähnt: https://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/

  1. Fügen Sie in der Skriptdatei eine Anweisung mit sourceURL wie "// @ sourceURL = foo.js" hinzu.
  2. Laden Sie das Skript mit jQuery $ .getScript () und das Skript ist in den Chrome-Entwicklungstools auf der Registerkarte "Quellen" verfügbar
Naga Kiran
quelle
1

Ihr Skript wird ausgeführt, Sie können es einfach nicht verwenden document.write. Verwenden Sie eine Warnung, um sie zu testen und die Verwendung zu vermeiden document.write. Die Anweisungen Ihrer js-Datei mit document.writewerden nicht ausgeführt und der Rest der Funktion wird ausgeführt.

Kunal Kinalekar
quelle
1

Dies ist meiner Meinung nach die beste Lösung. Google Analytics wird auf diese Weise injiziert.

var (function(){
    var p="https:" == document.location.protocol ? "https://" : "http://";
        d=document,
        g=d.createElement('script'),
        s=d.getElementsByTagName('script')[0];
        g.type='text/javascript';
        g.src=p+'url-to-your-script.js';
        s.parentNode.insertBefore(g,s); })();
dzona
quelle
1

Sie benötigen jQuery nicht, um ein Skript-DOM-Element zu erstellen . Es kann mit Vanilla ES6 wie folgt gemacht werden:

const script = "console.log('Did it work?')"
new Promise((resolve, reject) => {
  (function(i,s,o,g,r,a,m){
      a=s.createElement(o),m=s.getElementsByTagName(o)[0];
      a.innerText=g;
      a.onload=r;m.parentNode.insertBefore(a,m)}
  )(window,document,'script',script, resolve())
}).then(() => console.log('Sure did!'))

Es muss nicht in a eingeschlossen werden Promise, aber auf diese Weise können Sie das Versprechen beim Laden des Skripts auflösen und so die Race-Bedingungen für Skripte mit langer Laufzeit verhindern.

Josh Habdas
quelle
0

Skript an body anhängen:

$(document).ready(function() {
    $("<script>", {  src : "bootstrap.min.js",  type : "text/javascript" }).appendTo("body");
});
Cristian Olaru
quelle
0

Eine andere Möglichkeit, dies zu tun, wenn Sie Code anhängen möchten, besteht darin, die document.createElementMethode zu verwenden, aber dann .innerHTMLanstelle von .src.

var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.innerHTML = 'alert("Hey there... you just appended this script to the body");';
$("body").append( script );
Marc
quelle
0

Ich habe versucht , diese ein und funktioniert gut. Ersetzen Sie einfach das <Symbol damit \x3C.

// With Variable
var code = "\x3Cscript>SomeCode\x3C/script>";
$("#someElement").append(code);

oder

//Without Variable
$("#someElement").append("\x3Cscript>SomeCode\x3C/script>");

Sie können den Code hier testen .

Andrew
quelle
0

Kann so versuchen

var code = "<script></" + "script>";
$("#someElement").append(code);

Der einzige Grund, warum Sie dies nicht tun können, "<script></script>"ist, dass die Zeichenfolge in Javascript nicht zulässig ist, da die DOM-Ebene nicht analysieren kann, was js und was HTML ist.

VipinKundal
quelle
0

Ich habe ein npmPaket geschrieben, mit dem Sie eine HTML-Zeichenfolge, einschließlich Skript-Tags , an einen Container anhängen können die Skripte ausführen

Beispiel:

import appendHtml from 'appendhtml';

const html = '<p>Hello</p><script src="some_js_file.js"></script>'; 
const container = document.getElementById('some-div');

await appendHtml(html, container);

// appendHtml returns a Promise, some_js_file.js is now loaded and executed (note the await)

Finden Sie es hier: https://www.npmjs.com/package/appendhtml

Lukas
quelle
-1

Erstellen Sie einfach ein Element, indem Sie es mit jQuery analysieren.

<div id="someElement"></div>
<script>
    var code = "<script>alert(123);<\/script>";
    $("#someElement").append($(code));
</script>

Arbeitsbeispiel: https://plnkr.co/edit/V2FE28Q2eBrJoJ6PUEBz

Sanbor
quelle
Dies hat immer noch das gleiche Problem, einige Browser respektieren dies nicht.
Martin Massera
Könnten Sie mir bitte mitteilen, welche Browser und welche Version von jQuery Sie verwenden? Vielen Dank!
Sanbor