Avantages de createElement sur innerHTML?

Dans la pratique, quels sont les avantages de l'utilisation de createElement sur innerHTML? Je demande parce que je suis convaincu que l'utilisation de innerHTML est plus efficace en termes de performance et de lisibilité / maintenabilité des codes, mais mes coéquipiers ont décidé d'utiliser createElement comme approche de codage. Je veux simplement comprendre comment createElement peut être plus efficace.

Il existe plusieurs avantages à utiliser createElement au lieu de modifier innerHTML (par opposition à jeter ce qui est déjà là et le remplacer) en plus de la sécurité, comme Pekka déjà mentionné:

Préserve les références existantes aux éléments DOM lors de l'ajout d'éléments

Lorsque vous ajoutez (ou modifiez autrement) innerHTML , tous les noeuds DOM à l'intérieur de cet élément doivent être ré-analysés et recréés. Si vous avez enregistré des références aux noeuds, ils seront essentiellement inutiles, car ils ne sont plus ceux qui apparaissent.

Préserve les gestionnaires d'événements associés à tous les éléments DOM

Ce n'est vraiment qu'un cas spécial (bien que commun) du dernier. Le réglage innerHTML ne innerHTML pas automatiquement les gestionnaires d'événements aux nouveaux éléments qu'il crée, de sorte que vous devriez les suivre vous-même et les ajouter manuellement. La délégation de l'événement peut éliminer ce problème dans certains cas.

Peut être plus simple ou plus rapide dans certains cas

Si vous faites beaucoup d'ajouts, vous ne voulez certainement pas réinitialiser innerHTML car, bien que plus rapide pour des changements simples, re-analyser à plusieurs reprises et créer des éléments serait plus lent. La façon de contourner cela est de construire le HTML dans une chaîne et de définir innerHTML une fois que vous avez terminé. Selon la situation, la manipulation des cordes pourrait être plus lente que de créer des éléments et de les ajouter.

De plus, le code de manipulation des chaînes peut être plus compliqué (surtout si vous voulez qu'il soit en sécurité).

Voici une fonction que j'utilise parfois qui rend plus pratique d'utiliser createElement .

 function isArray(a) { return Object.prototype.toString.call(a) === "[object Array]"; } function make(desc) { if (!isArray(desc)) { return make.call(this, Array.prototype.slice.call(arguments)); } var name = desc[0]; var attributes = desc[1]; var el = document.createElement(name); var start = 1; if (typeof attributes === "object" && attributes !== null && !isArray(attributes)) { for (var attr in attributes) { el[attr] = attributes[attr]; } start = 2; } for (var i = start; i < desc.length; i++) { if (isArray(desc[i])) { el.appendChild(make(desc[i])); } else { el.appendChild(document.createTextNode(desc[i])); } } return el; } 

Si vous l'appelez comme ceci:

 make(["p", "Here is a ", ["a", { href:"http://www.google.com/" }, "link"], "."]); 

Vous obtenez l'équivalent de ce HTML:

 <p>Here is a <a href="http://www.google.com/">link</a>.</p> 

Bien que innerHTML soit plus rapide, je ne suis pas d'accord pour dire qu'il est mieux en termes de lisibilité ou de maintenance. Il peut être plus court de mettre tout dans une seule chaîne, mais un code plus court n'est pas toujours nécessairement plus durable.

La concaténation de chaîne ne s'améliore pas lorsque les éléments DOM dynamiques doivent être créés car les ouvertures et fermetures de plus et de citation deviennent difficiles à suivre. Considérons ces exemples:

L'élément résultant est un div avec deux travées internes dont le contenu est dynamique. L'un des noms de classe (guerrier) à l'intérieur de la première portée est également dynamique.

 <div> <span class="person warrior">John Doe</span> <span class="time">30th May, 2010</span> </div> 

Supposons que les variables suivantes sont déjà définies:

 var personClass = 'warrior'; var personName = 'John Doe'; var date = '30th May, 2010'; 

En utilisant juste innerHTML et tout en tout en une seule chaîne, on obtient:

 someElement.innerHTML = "<div><span class='person " + personClass + "'>" + personName + "</span><span class='time'>" + date + "</span></div>"; 

Le désordre ci-dessus peut être nettoyé avec l'aide de remplacements de cordes pour éviter d'ouvrir et de fermer les cordes à chaque fois. Même pour les remplacements de texte simples, je préfère utiliser le replace au lieu de la concaténation de chaîne.

Il s'agit d'une fonction simple qui prend un objet de clés et de valeurs de remplacement et les remplace dans la chaîne. Il suppose que les clés sont préfixées avec $ pour indiquer qu'elles sont une valeur spéciale. Il ne fait aucun cas de bord d'échappement ou de manipulation où $ apparaît dans la valeur de remplacement, etc.

 function replaceAll(string, map) { for(key in map) { string = string.replace("$" + key, map[key]); } return string; } var string = '<div><span class="person $type">$name</span><span class="time">$date</span></div>'; var html = replaceAll(string, { type: personClass, name: personName, date: date }); someElement.innerHTML = html; 

Cela peut être amélioré en séparant les attributs, le texte, etc. tout en construisant l'objet pour obtenir plus de contrôle programmatique sur la construction de l'élément. Par exemple, avec MooTools, nous pouvons transmettre les propriétés de l'objet en tant que carte. Ceci est certainement plus durable, et je discuterai plus facilement. JQuery 1.4 utilise une syntaxe similaire pour passer une carte pour l'initialisation des objets DOM.

 var div = new Element('div'); var person = new Element('span', { 'class': 'person ' + personClass, 'text': personName }); var when = new Element('span', { 'class': 'time', 'text': date }); div.adopt([person, when]); 

Je n'appellerais pas l'approche pure de DOM ci-dessous pour être plus lisible que celles ci-dessus, mais cela est certainement plus maintenable car nous ne devons pas suivre les citations d'ouverture / de fermeture et de nombreux signes plus.

 var div = document.createElement('div'); var person = document.createElement('span'); person.className = 'person ' + personClass; person.appendChild(document.createTextNode(personName)); var when = document.createElement('span'); ​when.className = 'date​​​​​​'; when.appendChild(document.createTextNode(date)); ​div.appendChild(person); div.appendChild(when); 

La version la plus lisible résulterait probablement d'une sorte de modèle de JavaScript .

 <div id="personTemplate"> <span class="person <%= type %>"><%= name %></span> <span class="time"><%= date %></span> </div> var div = $("#personTemplate").create({ name: personName, type: personClass, date: date }); 

L'utilisateur Bobince met un certain nombre de inconvénients très bien dans sa critique de jQuery .

… De plus, vous pouvez faire un div en disant $ ('' + message + '') au lieu d'avoir à se ranger avec document.createElement ('div') et les nœuds de texte. Hooray! Seulement … accrochez-vous. Vous ne vous êtes pas échappé à ce code HTML, et vous avez probablement créé un trou de sécurité pour les scripts entre sites, uniquement du côté client cette fois. Et après avoir passé si longtemps à nettoyer votre PHP pour utiliser htmlspecialchars sur le côté serveur, aussi. C'est dommage. Ah bien, personne ne se préoccupe vraiment de la justesse ou de la sécurité, n'est-ce pas?

JQuery n'est pas entièrement responsable de cela. Après tout, la propriété innerHTML existe depuis des années et s'est déjà révélée plus populaire que DOM. Mais la bibliothèque encourage certainement ce style de codage.

En ce qui concerne la performance: InnerHTML va certainement être plus lent, car il doit être analysé et converti en interne en éléments DOM (peut-être en utilisant la méthode createElement ).

InnerHTML est plus rapide dans tous les navigateurs selon la référence de quirksmode fournie par @Pointy.

En ce qui concerne la lisibilité et la facilité d'utilisation, vous me trouverez en choisissant createElement sur createElement n'importe quel jour de la semaine dans la plupart des projets. Mais comme vous pouvez le voir, plusieurs points parlent pour createElement .

Vous devez utiliser createElement si vous souhaitez conserver des références dans votre code. InnerHTML peut parfois créer un bug qui est difficile à repérer.

Code HTML:

 <p id="parent">sample <span id='test'>text</span> about anything</p> 

Code JS:

 var test = document.getElementById("test"); test.style.color = "red"; //1 - it works document.getElementById("parent").innerHTML += "whatever"; test.style.color = "green"; //2 - oooops 

1) vous pouvez changer la couleur

2) vous ne pouvez plus changer de couleur ou autre chose, car dans la ligne ci-dessus, vous avez ajouté quelque chose à innerHTML et tout est recréé et vous avez accès à quelque chose qui n'existe plus. Pour le changer, vous devez encore obtenir ELEMENTById .

Vous devez vous rappeler que cela affecte également tous les événements. Vous devez ré-appliquer les événements.

InnerHTML est génial, car il est plus rapide et plus facile à lire, mais il faut faire attention et l'utiliser avec prudence. Si vous savez ce que vous faites, vous serez OK.

J'ai créé un fichier xml pour stocker un cadre d'information.

 <?xml version="1.0" encoding="utf-8"?> <div id="structure"> <div class="form-group"> <label for="pharasalEn">Pharasal En</label> <input type="text" class="form-control" name="pharasalEn"/> </div> <div class="form-group"> <label for="pharasalVi">Pharasal Vi</label> <input type="text" class="form-control" name="pharasalVi"/> </div> <div class="form-group"> <label for="exampleEn">Example En</label> <input type="text" class="form-control" name="exampleEn"/> </div> <div class="form-group"> <label for="exampleVi">Example Vi</label> <input type="text" class="form-control" name="exampleVi"/> </div> <div class="form-group"> <input type="button" value="Add structure" class="btn btn-default add" onClick="addStructure()"/> <input type="button" value="Delete structure" class="btn btn-default" onClick="deleteStructure(this)"/> </div> </div> 

Ensuite, j'utilise ajax pour récupérer des informations sur les images. Créez un DOM puis innerHTML le xml ci-dessus dans dom.Then j'ai édité les informations sur dom.Then appendchild qui dom dans un conteneur.

 function addStructure(){ var xml = new XMLHttpRequest(); xml.onreadystatechange = function(){ if(this.readyState == 4 && this.status == 200){ var xml = this.responseXML; var e = xml.getElementById("structure"); var list= document.getElementById("listStructure"); var div = document.createElement("div"); div.setAttribute("class", "structure"); div.innerHTML = e.innerHTML; list.appendChild(div); } } xml.open("GET", "object.xml", true); xml.send(); } 

Un problème est que la charge xml est stockée dans le cashe. Lorsque le changement xml, le cache n'est pas modifié, le contenu n'a pas été mis à jour. Je l'ai donc réparé.

 window.onload = function() { if(!window.location.hash) { window.location = window.location + '#loaded'; window.location.reload(); } } 

Il semble un peu compliqué et peut courir plus longtemps. Mais quand je change, je modifie simplement le contenu de mon fichier xml.
Remarque: j'utilise Google translate pour mon contenu.