Existe-t-il une bonne pratique pour générer du HTML avec javascript


103

J'appelle un service Web qui renvoie un tableau d'objets en JSON. Je veux prendre ces objets et remplir un div avec du HTML. Disons que chaque objet contient une URL et un nom.

Si je voulais générer le HTML suivant pour chaque objet:

<div><img src="the url" />the name</div>

Existe-t-il une meilleure pratique pour cela? Je peux voir quelques façons de le faire:

  1. Concaténer les chaînes
  2. Créer des éléments
  3. Utilisez un plugin de création de modèles
  4. Générez le html sur le serveur, puis servez via JSON.

1
Vous pouvez également vérifier le soulignement js: documentcloud.github.com/underscore/#template Il joue très bien avec backbone.js
luacassus

Le choix entre 1-4: dépend de la quantité de contenu à injecter (préférez 4 pour plus grand) combien de parties html différentes devront être ajoutées au total (3 ou 4). ce que sb connaît. (Influence sur le temps de développement). Si vous ne connaissez aucun outil, c'est juste un petit modal qui sera injecté une fois que je ne connais pas un meilleur moyen que le pur js de le faire (1-2)
partizanos

Réponses:


68

Les options n ° 1 et n ° 2 seront vos options simples les plus immédiates, cependant, pour les deux options, vous allez ressentir l'impact sur les performances et la maintenance en construisant des chaînes ou en créant des objets DOM.

La création de modèles n'est pas si immature que cela, et vous le voyez apparaître dans la plupart des principaux frameworks Javascript.

Voici un exemple dans JQuery Template Plugin qui vous permettra d'économiser les performances, et qui est vraiment très simple:

var t = $.template('<div><img src="${url}" />${name}</div>');

$(selector).append( t , {
     url: jsonObj.url,
     name: jsonObj.name
});

Je dis d'aller sur la voie cool (et plus performante, plus maintenable) et d'utiliser des modèles.


13
JQuery templating semble être mort, voir stackoverflow.com/questions/7911732/…
James McMahon

4
@Jim Fiorato: le lien est mort: s
Adrien Be le

2
Link est mort, comme le souligne Adrien. Je vous
suggère de

1
Quelqu'un peut-il expliquer, pourquoi une réponse basée sur jQuery est la réponse acceptée? Je doute que ce soit la meilleure pratique!
WoIIe

1
@WoIIe Pire encore, le plugin jQuery est mort, donc cette réponse est obsolète.
Franklin Yu

13

Si vous devez absolument concaténer des chaînes, au lieu de la normale:

var s="";
for (var i=0; i < 200; ++i) {s += "testing"; }

utilisez un tableau temporaire:

var s=[];
for (var i=0; i < 200; ++i) { s.push("testing"); }
s = s.join("");

L'utilisation de tableaux est beaucoup plus rapide, en particulier dans IE. J'ai fait quelques tests avec des chaînes il y a quelque temps avec IE7, Opera et FF. Opera n'a pris que 0.4s pour effectuer le test, mais IE7 n'avait pas terminé après 20 MINUTES !!!! (Non, je ne plaisante pas.) Avec le tableau IE était très rapide.


J'ai changé de navigateur il y a longtemps, donc je ne souffre pas beaucoup. IE était un navigateur horrible mais il s'améliore. Mais je doute que je reviendrai jamais.
certains

1
La lenteur des performances observée dans la première méthode est probablement due au fait que la chaîne de résultat doit être réallouée 200 fois et que les allocations de mémoire peuvent être lentes. Après deux itérations, vous avez "testingtesting". Après trois itérations, cette chaîne est jetée et de la mémoire avec suffisamment de place pour "testingtestingtesting" est allouée. Et ainsi de suite 200 fois avec une longueur progressivement croissante. Cependant, s.join () alloue une nouvelle chaîne en conséquence qui est suffisamment longue pour les contenir toutes, puis copie dans chacune d'elles. Une allocation, beaucoup plus rapide.
EricP

1
@JoeCoder, d'accord, c'est un algorithme de Shlemiel The Painter. joelonsoftware.com/articles/fog0000000319.html
Jodrell

8

L'une ou l'autre des deux premières options est à la fois courante et acceptable.

Je vais donner des exemples de chacun dans Prototype .

// assuming JSON looks like this:
// { 'src': 'foo/bar.jpg', 'name': 'Lorem ipsum' }

Approche n ° 1:

var html = "<div><img src='#{src}' /> #{name}</div>".interpolate(json);
$('container').insert(html); // inserts at bottom

Approche n ° 2:

var div = new Element('div');
div.insert( new Element('img', { src: json.src }) );
div.insert(" " + json.name);
$('container').insert(div); // inserts at bottom

Construire en générant explicitement le HTML avec des chaînes plutôt qu'avec des éléments DOM est plus performant (en supposant que la concaténation de chaînes n'est pas un vrai problème) et lisible.
Rodrick Chapman

Dans IE, la concaténation de chaînes est toujours un problème. Utilisez plutôt un tableau.
certains

7

Une approche peut-être plus moderne consiste à utiliser un langage de création de modèles tel que Moustache , qui a des implémentations dans de nombreux langages, y compris javascript. Par exemple:

var view = {
  url: "/hello",
  name: function () {
    return 'Jo' + 'hn';
  }
};

var output = Mustache.render('<div><img src="{{url}}" />{{name}}</div>', view);

Vous obtenez même un avantage supplémentaire: vous pouvez réutiliser les mêmes modèles à d'autres endroits, comme côté serveur.

Si vous avez besoin de modèles plus compliqués (instructions if, boucles, etc.), vous pouvez utiliser Handlebars qui a plus de fonctionnalités et est compatible avec Moustache.


6

Voici un exemple, en utilisant mon plug-in Simple Templates pour jQuery:

var tmpl = '<div class="#{classname}">#{content}</div>';
var vals = {
    classname : 'my-class',
    content   : 'This is my content.'
};
var html = $.tmpl(tmpl, vals);

1
Soigné. J'aurais pu utiliser quelque chose qui ressemble à un gros projet il y a quelques mois.
Rodrick Chapman

Oui. Concis et soigné!
ajitweb

4

Vous pouvez ajouter le modèle HTML à votre page dans un div caché, puis utiliser cloneNode et les fonctionnalités de requête de votre bibliothèque préférée pour le remplir.

/* CSS */
.template {display:none;}

<!--HTML-->
<div class="template">
  <div class="container">
    <h1></h1>
    <img src="" alt="" />
  </div>
</div>

/*Javascript (using Prototype)*/
var copy = $$(".template .container")[0].cloneNode(true);
myElement.appendChild(copy);
$(copy).select("h1").each(function(e) {/*do stuff to h1*/})
$(copy).select("img").each(function(e) {/*do stuff to img*/})

3

Divulgation: Je suis le mainteneur de BOB.

Il existe une bibliothèque javascript qui rend ce processus beaucoup plus facile appelée BOB .

Pour votre exemple spécifique:

<div><img src="the url" />the name</div>

Cela peut être généré avec BOB par le code suivant.

new BOB("div").insert("img",{"src":"the url"}).up().content("the name").toString()
//=> "<div><img src="the url" />the name</div>"

Ou avec la syntaxe plus courte

new BOB("div").i("img",{"src":"the url"}).up().co("the name").s()
//=> "<div><img src="the url" />the name</div>"

Cette bibliothèque est assez puissante et peut être utilisée pour créer des structures très complexes avec insertion de données (similaire à d3), par exemple:

data = [1,2,3,4,5,6,7]
new BOB("div").i("ul#count").do(data).i("li.number").co(BOB.d).up().up().a("a",{"href": "www.google.com"}).s()
//=> "<div><ul id="count"><li class="number">1</li><li class="number">2</li><li class="number">3</li><li class="number">4</li><li class="number">5</li><li class="number">6</li><li class="number">7</li></ul></div><a href="www.google.com"></a>"

BOB ne prend actuellement pas en charge l'injection des données dans le DOM. C'est sur la todolist. Pour l'instant, vous pouvez simplement utiliser la sortie avec JS normal, ou jQuery, et la placer où vous le souhaitez.

document.getElementById("parent").innerHTML = new BOB("div").insert("img",{"src":"the url"}).up().content("the name").s();
//Or jquery:
$("#parent").append(new BOB("div").insert("img",{"src":"the url"}).up().content("the name").s());

J'ai créé cette bibliothèque parce que je n'étais satisfait d'aucune des alternatives comme jquery et d3. Le code est très compliqué et difficile à lire. Travailler avec BOB est à mon avis, ce qui est évidemment biaisé, beaucoup plus agréable.

BOB est disponible sur Bower , vous pouvez donc l'obtenir en exécutant bower install BOB.


2

Existe-t-il une meilleure pratique pour cela? Je peux voir quelques façons de le faire:

  1. Concaténer les chaînes
  2. Créer des éléments
  3. Utilisez un plugin de création de modèles
  4. Générez le html sur le serveur, puis servez via JSON.

1) Ceci est une option. Construisez le html avec JavaScript côté client, puis injectez-le dans le DOM dans son ensemble.

Notez qu'il y a un paradigme derrière cette approche: le serveur ne produit que des données et (en cas d'interaction) reçoit les données du client de manière asyncronale avec des requêtes AJAX. Le code côté client fonctionne comme une application Web JavaScript autonome.

L'application Web peut fonctionner, rendre l'interface, même sans que le serveur soit en place (bien sûr, elle n'affichera aucune donnée ni n'offrira aucune sorte d'interaction).

Ce paradigme est souvent adopté ces derniers temps et des frameworks entiers sont construits autour de cette approche (voir backbone.js par exemple).

2) Pour des raisons de performances, lorsque cela est possible, il est préférable de créer le code HTML dans une chaîne, puis de l'injecter dans son ensemble dans la page.

3) Ceci est une autre option, ainsi que l'adoption d'un cadre d'application Web. D'autres utilisateurs ont publié divers moteurs de création de modèles disponibles. J'ai l'impression que vous avez les compétences pour les évaluer et décider de suivre ou non cette voie.

4) Une autre option. Mais servez-le sous forme de texte brut / html; pourquoi JSON? Je n'aime pas cette approche car mélange PHP (votre langage serveur) avec Html. Mais je l'adopte souvent comme un compromis raisonnable entre les options 1 et 4 .


Ma réponse: vous regardez déjà dans la bonne direction.

Je suggère d'adopter une approche entre 1 et 4 comme je le fais. Sinon, adoptez un framework Web ou un moteur de création de modèles.

Juste mon avis basé sur mon expérience ...

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.