Was sind Alternativen zu document.write?

71

In Tutorials habe ich gelernt, zu verwenden document.write. Jetzt verstehe ich, dass dies von vielen verpönt wird. Ich habe es versucht print(), aber dann wird es buchstäblich an den Drucker gesendet.

Welche Alternativen sollte ich verwenden und warum sollte ich sie nicht verwenden document.write? Sowohl w3schools als auch MDN verwenden document.write.

DarkLightA
quelle
3
print()beschließt zu window.print().
Alex
2
JavaScript print()ist nicht dasselbe wie PHP print(). JS sendet die Seite buchstäblich an den Drucker und PHP gibt einfach Code aus.
Drazzah

Antworten:

86

Der Grund, warum Ihr HTML ersetzt wird, liegt an einer bösen JavaScript-Funktion : document.write().

Es ist definitiv "schlechte Form". Es funktioniert nur mit Webseiten, wenn Sie es beim Laden der Seite verwenden. Wenn Sie es zur Laufzeit verwenden, wird Ihr gesamtes Dokument durch die Eingabe ersetzt. Und wenn Sie es als strenge XHTML-Struktur anwenden, ist es nicht einmal gültiger Code.


das Problem:

document.writeschreibt in den Dokumentstrom. Wenn Sie document.writeein geschlossenes (oder geladenes) Dokument aufrufen document.open, wird automatisch aufgerufen, wodurch das Dokument gelöscht wird.

- Zitat aus dem MDN

document.write()hat zwei Handlanger document.open(), und document.close(). Wenn das HTML-Dokument geladen wird, ist das Dokument "geöffnet". Wenn das Dokument vollständig geladen wurde, wurde das Dokument "geschlossen". Wenn Sie document.write()an dieser Stelle verwenden, wird Ihr gesamtes (geschlossenes) HTML-Dokument gelöscht und durch ein neues (offenes) Dokument ersetzt. Dies bedeutet, dass Ihre Webseite sich selbst gelöscht und eine neue Seite geschrieben hat - von Grund auf neu.

Ich glaube, document.write()dass der Browser ebenfalls eine Leistungsminderung aufweist (korrigieren Sie mich, wenn ich falsch liege).


ein Beispiel:

Dieses Beispiel schreibt Ausgabe an das HTML - Dokument , nachdem die Seite geladen wird. document.write()Die bösen Mächte von Watch löschen das gesamte Dokument, wenn Sie auf die Schaltfläche "Ausrotten" klicken:

I am an ordinary HTML page.  I am innocent, and purely for informational purposes. Please do not <input type="button" onclick="document.write('This HTML page has been succesfully exterminated.')" value="exterminate"/>
me!


die Alternativen:

  • .innerHTML Dies ist eine wunderbare Alternative, aber dieses Attribut muss an das Element angehängt werden, in das Sie den Text einfügen möchten.

Beispiel: document.getElementById('output1').innerHTML = 'Some text!';

  • .createTextNode()ist die vom W3C empfohlene Alternative .

Beispiel: var para = document.createElement('p'); para.appendChild(document.createTextNode('Hello, '));

HINWEIS: Es ist bekannt, dass dies zu Leistungseinbußen führt (langsamer als .innerHTML). Ich empfehle .innerHTMLstattdessen zu verwenden.


das Beispiel mit der .innerHTMLAlternative:

I am an ordinary HTML page. 
I am innocent, and purely for informational purposes. 
Please do not 
<input type="button" onclick="document.getElementById('output1').innerHTML = 'There was an error exterminating this page. Please replace <code>.innerHTML</code> with <code>document.write()</code> to complete extermination.';" value="exterminate"/>
 me!
<p id="output1"></p>

Drazzah
quelle
Das Böse beginnt also erst, nachdem das Dokument geschlossen wurde? Gibt es neben der Unmodalität auch Nachteile bei der Verwendung von document.write? Gibt es praktische Unsicherheiten darüber, wann das Dokument geschlossen wird?
Bob Stein
@ BobStein-VisiBone, ja, document.write()kann während des Ladens der Seite aufgerufen werden, während der Browser die Seite analysiert. Sobald die Seite analysiert / geladen wurde, wird beim Aufrufen dieser Funktion auch aufgerufen document.open(), wodurch die Seite gelöscht und von vorne begonnen wird. Ich kann mir keinen Grund vorstellen, die Funktion während des Ladens der Seite nicht zu verwenden, außer aus Gründen der Konsistenz mit der Art und Weise, wie Sie einer Seite zu einem anderen Zeitpunkt Inhalt hinzufügen. Das Dokument wird geschlossen, sobald der Browser das Parsen des Dokuments abgeschlossen hat.
Drazzah
document.write()scheint immer noch die beste Lösung für den lokalen Fallback von CDN zu sein . Ich habe getElementById / innerHTML noch nicht ausprobiert, aber eine createElement / insertBefore-Lösung stellt sich als nicht synchron heraus .
Bob Stein
2
@Godisgood, document.write hat auf keinen Fall Leistungsprobleme, da es genau dieselbe Funktion ist, die von Browsern verwendet wird, wenn sie die anfängliche HTTP-Antwort laden.
Pacerier
@Pacerier Ja, aber ich meinte, es ist langsamer zu verwenden, document.write()nachdem die Seiten geladen wurden, da das Dokument gelöscht und bei jedem Aufruf der Funktion erneut geöffnet werden muss. .innerHTMLmacht nichts davon, also bin ich mir ziemlich sicher, dass ich gelesen habe, dass es doch schneller ist. Ich werde nach einer Quelle suchen, um das zu belegen. Ich glaube, es document.write()ist schnell, wenn Sie es verwenden, während die Seite bereits geöffnet ist.
Drazzah
24

Hier ist Code, der document.write ersetzen soll:

document.write=function(s){
    var scripts = document.getElementsByTagName('script');
    var lastScript = scripts[scripts.length-1];
    lastScript.insertAdjacentHTML("beforebegin", s);
}
Adrian Kalbarczyk
quelle
schöner tipp. Ist es Crossbrowser? Ich habe es auf Chrome getestet und funktioniert.
Pons
2
Funktioniert das nicht, wenn die Seite keine Skripte enthält?
Noyo
Nun, es würde zumindest auf der Seite sein (wo immer Sie diese Funktion platzieren), aber was ist, wenn sich das einzige Skript im <head> </ head> befindet? Der Schlüssel, den er erwähnt, ist die Funktion insertAdjacentHTML.
Lonnie Best
Seltsamerweise hatte ich bis heute keine E-Mails, die jemand kommentierte. LOL. @Pons - es sollte browserübergreifend sein, ich weiß aber nichts über IE.
Adrian Kalbarczyk
@Noyo - normalerweise verwenden Sie document.write in <script> auf der Seite, wie Github GISTs: gist.github.com/adriank/7436248.js
Adrian Kalbarczyk
10

Lassen Sie hier nur eine Notiz fallen, um zu sagen, dass die Verwendung document.writeaufgrund von Leistungsproblemen (synchrone DOM-Injektion und Auswertung) zwar stark verpönt ist , es jedoch auch keine tatsächliche 1: 1-Alternative gibt, wenn Sie document.writeSkript-Tags bei Bedarf injizieren.

Es gibt viele gute Möglichkeiten, dies zu vermeiden (z. B. Skriptlader wie RequireJS , die Ihre Abhängigkeitsketten verwalten), aber sie sind invasiver und werden daher am besten auf der gesamten Site / Anwendung verwendet.

James M. Greene
quelle
9

Sie können die insertAdjacentHTML- Methode und document.currentScript kombinieren Eigenschaft .

Die insertAdjacentHTML()Methode der Element-Schnittstelle analysiert den angegebenen Text als HTML oder XML und fügt die resultierenden Knoten an einer bestimmten Position in den DOM-Baum ein :

  • 'beforebegin': Vor dem Element selbst.
  • 'afterbegin': Nur innerhalb des Elements, vor seinem ersten Kind.
  • 'beforeend': Nur innerhalb des Elements, nach seinem letzten Kind.
  • 'afterend': Nach dem Element selbst.

Die document.currentScriptEigenschaft gibt das <script>Element zurück, dessen Skript gerade verarbeitet wird. Die beste Position ist vor dem Start - neuer HTML- Code wird vor sich <script>selbst eingefügt . Um document.writedem nativen Verhalten zu entsprechen, würde man den Text nach dem Ende positionieren , aber dann werden die Knoten von aufeinanderfolgenden Aufrufen der Funktion nicht in der Reihenfolge platziert, in der Sie sie aufgerufen haben (wie dies der document.writeFall ist), sondern in umgekehrter Reihenfolge. Die Reihenfolge, in der Ihr HTML angezeigt wird, ist wahrscheinlich wichtiger als die Position, in der sie relativ zum <script>Tag platziert sind, daher die Verwendung von beforebegin .

document.currentScript.insertAdjacentHTML(
  'beforebegin', 
  'This is a document.write alternative'
)

Sorin
quelle
Obwohl dies die Frage beantworten kann, geben Sie bitte jede Erklärung, die Sie können, um sicherzustellen, dass die Leute verstehen, was hier passiert.
Randy
Dank dieses Kommentars hier ist mein Problem behoben. Ich habe hier erklärt, was das Problem war und was für mich funktioniert hat: stackoverflow.com/a/64610187/7266835
K. Shaikh
7

Die Frage hängt davon ab, was Sie tatsächlich versuchen.

Normalerweise anstatt das zu tun document.writekönnen Sie verwenden , someElement.innerHTMLoder besser, document.createElementmit einemsomeElement.appendChild .

Sie können auch eine Bibliothek wie jQuery und die darin enthaltenen Änderungsfunktionen verwenden: http://api.jquery.com/category/manipulation/

Wolph
quelle
4

Versuchen Sie, getElementById () oder getElementsByName () zu verwenden, um auf ein bestimmtes Element zuzugreifen, und verwenden Sie dann die innerHTML-Eigenschaft:

<html>
    <body>
        <div id="myDiv1"></div>
        <div id="myDiv2"></div>
    </body>

    <script type="text/javascript">
        var myDiv1 = document.getElementById("myDiv1");
        var myDiv2 = document.getElementById("myDiv2");

        myDiv1.innerHTML = "<b>Content of 1st DIV</b>";
        myDiv2.innerHTML = "<i>Content of second DIV element</i>";
    </script>
</html>

quelle
Hat nicht ganz geklappt. Benötigen Sie keine <body> -Tags und <\/b>das Skript?
DarkLightA
@DarkLightA: Die von Ihnen eingegebene Standardquelle ist nicht dieselbe wie die obere. und auf der anderen Seite ist es im Javascript-Fenster! Die Quelle hat beide Quelltypen, HTML und Javascript. Erstellen Sie mit dieser Quelle eine HTML-Datei auf Ihrem Desktop und öffnen Sie sie.
4

Ich sehe das Problem nicht mit document.write. Wenn Sie es verwenden, bevor das onloadEreignis ausgelöst wird, wie Sie es vermutlich sind, um beispielsweise Elemente aus strukturierten Daten zu erstellen, ist es das geeignete Werkzeug. Die Verwendung bietet keinen LeistungsvorteilinsertAdjacentHTML oder explizite Hinzufügung von Knoten zum DOM nach dessen Erstellung . Ich habe es gerade auf drei verschiedene Arten mit einem alten Skript getestet, mit dem ich einmal eingehende Modemanrufe für einen 24/7-Dienst auf einer Bank von 4 Modems geplant habe.

Bis es fertig ist, erstellt dieses Skript über 3000 DOM-Knoten, hauptsächlich Tabellenzellen. Auf einem 7 Jahre alten PC, auf dem Firefox unter Vista ausgeführt wird, dauert diese kleine Übung weniger als 2 Sekunden, document.writewenn eine lokale 12-KB-Quelldatei und drei 1px-GIFs verwendet werden, die etwa 2000 Mal wiederverwendet werden. Die Seite wird nur vollständig erstellt und ist bereit, Ereignisse zu verarbeiten.

Die Verwendung insertAdjacentHTMList kein direkter Ersatz, da der Browser Tags schließt, für die das Skript geöffnet bleiben muss, und doppelt so lange dauert, bis eine verstümmelte Seite erstellt wird. Schreiben Sie alle Teile in eine Zeichenfolge und übergeben Sie sie dann aninsertAdjacentHTML dauert noch länger, aber zumindest erhalten Sie die Seite wie geplant. Andere Optionen (wie das manuelle Neuerstellen des DOM für einen Knoten) sind so lächerlich, dass ich nicht einmal dorthin gehe.

Manchmal document.writeist das Ding zu benutzen. Die Tatsache, dass es sich um eine der ältesten Methoden in JavaScript handelt, spricht nicht dagegen, sondern dafür - es handelt sich um hochoptimierten Code, der genau das tut, was er beabsichtigt hat und seit seiner Einführung getan hat.

Es ist schön zu wissen, dass es alternative Nachlademethoden gibt, aber es muss verstanden werden, dass diese für einen ganz anderen Zweck bestimmt sind. Ändern des DOM, nachdem es erstellt und ihm Speicher zugewiesen wurde. Die Verwendung dieser Methoden ist von Natur aus ressourcenintensiver, wenn Ihr Skript den HTML-Code schreiben soll, aus dem der Browser das DOM erstellt.

Schreiben Sie es einfach und lassen Sie den Browser und den Dolmetscher die Arbeit erledigen. Dafür sind sie da.

PS: Ich habe gerade mit einem onloadParameter im bodyTag getestet und selbst zu diesem Zeitpunkt ist das Dokument noch vorhanden openund document.write()funktioniert wie beabsichtigt. Außerdem ist in der neuesten Version von Firefox kein Leistungsunterschied zwischen den verschiedenen Methoden erkennbar. Natürlich gibt es eine Menge Caching, das wahrscheinlich irgendwo im Hardware- / Software-Stack stattfindet, aber genau darum geht es - lassen Sie die Maschine die Arbeit erledigen. Auf einem billigen Smartphone kann dies jedoch einen Unterschied machen. Prost!

bebopalooblog
quelle
-5

Ich bin mir nicht sicher, ob das genau funktionieren wird, aber ich habe darüber nachgedacht

var docwrite = function(doc) {               
    document.write(doc);          
};

Dies löste das Problem mit den Fehlermeldungen für mich.

Mlee
quelle