¿Existe una buena práctica para generar html con javascript?

103

Estoy llamando a un servicio web que devuelve una matriz de objetos en JSON. Quiero tomar esos objetos y llenar un div con HTML. Digamos que cada objeto contiene una URL y un nombre.

Si quisiera generar el siguiente HTML para cada objeto:

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

¿Existe una buena práctica para esto? Puedo ver algunas formas de hacerlo:

  1. Concatenar cadenas
  2. Crear elementos
  3. Usa un complemento de plantillas
  4. Genere el html en el servidor, luego sirva a través de JSON.
ckarbass
fuente
1
También puede verificar el guión bajo js: documentcloud.github.com/underscore/#template Funciona muy bien con backbone.js
luacassus
La elección entre 1 y 4: depende de la cantidad de contenido que se va a inyectar (prefiera 4 para más grande) cuántas partes html diferentes deberán agregarse en total (3 o 4). con lo que sb está familiarizado. (Influencia en el tiempo de desarrollo). Si no conoce ninguna herramienta, es solo un pequeño modal que se inyectará una vez que no conozca una mejor manera que js puros para hacerlo (1-2)
partizanos

Respuestas:

68

Las opciones n. ° 1 y n. ° 2 serán sus opciones directas más inmediatas, sin embargo, para ambas opciones, sentirá el impacto en el rendimiento y el mantenimiento al construir cadenas o crear objetos DOM.

La creación de plantillas no es tan inmadura, y la está viendo emergente en la mayoría de los principales marcos de Javascript.

Aquí hay un ejemplo en el complemento de plantilla de JQuery que le ahorrará el impacto en el rendimiento y es realmente muy sencillo:

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

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

Yo digo que vaya por el camino fresco (y mejor rendimiento, más fácil de mantener) y use plantillas.

Jim Fiorato
fuente
13
Las plantillas de JQuery parecen estar muertas, consulte stackoverflow.com/questions/7911732/…
James McMahon
4
@Jim Fiorato: el enlace está muerto: s
Adrien Be
2
Link está muerto, como señala Adrien. Sugiero que actualice su respuesta para incluir: Moustache.js
Mr. Polywhirl
1
¿Alguien puede explicar por qué una respuesta basada en jQuery es la aceptada? ¡Dudo que esta sea la mejor práctica!
WoIIe
1
@WoIIe Incluso peor, el complemento jQuery está muerto, por lo que esta respuesta está desactualizada.
Franklin Yu
13

Si es absolutamente necesario concatenar cadenas, en lugar de lo normal:

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

usar una matriz temporal:

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

El uso de matrices es mucho más rápido, especialmente en IE. Hice algunas pruebas con cadenas hace un tiempo con IE7, Opera y FF. Opera tomó solo 0.4 segundos para realizar la prueba, ¡pero IE7 no había terminado después de 20 MINUTOS! (No, no bromeo.) Con array IE fue muy rápido.

algunos
fuente
Cambié de navegador hace mucho tiempo, así que no sufro tanto. IE era un navegador horrible, pero está mejorando. Pero dudo que alguna vez vuelva.
algunos
1
Es probable que el rendimiento lento observado en el primer método se deba a que la cadena de resultado debe reasignarse 200 veces y las asignaciones de memoria pueden ser lentas. Después de dos iteraciones tienes "testingtesting". Después de tres iteraciones, esa cadena se desecha y se asigna memoria con espacio suficiente para "testingtestingtesting". Y así sucesivamente 200 veces con una longitud que aumenta gradualmente. Sin embargo, s.join () asigna una nueva cadena como resultado que es lo suficientemente larga para que quepan todas, luego copia en cada una. Una asignación, mucho más rápido.
EricP
1
@JoeCoder, estuvo de acuerdo, es un algoritmo de Shlemiel The Painter. joelonsoftware.com/articles/fog0000000319.html
Jodrell
8

Cualquiera de las dos primeras opciones es común y aceptable.

Daré ejemplos de cada uno en Prototype .

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

Enfoque n. ° 1:

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

Enfoque 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
guardar la torre del reloj
fuente
Generar HTML explícitamente con cadenas en lugar de elementos DOM es más eficaz (asumiendo que la concatenación de cadenas no es un problema real) y legible.
Rodrick Chapman
En IE, la concatenación de cadenas siempre es un problema. En su lugar, use una matriz.
alrededor del
7

Quizás un enfoque más moderno es utilizar un lenguaje de plantillas como Moustache , que tiene implementaciones en muchos idiomas, incluido javascript. Por ejemplo:

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

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

Incluso obtiene un beneficio adicional: puede reutilizar las mismas plantillas en otros lugares, como el lado del servidor.

Si necesita plantillas más complicadas (declaraciones if, loops, etc.), puede usar Handlebars que tiene más funciones y es compatible con Moustache.

Tzach
fuente
6

Aquí hay un ejemplo, usando mi complemento de Plantillas simples para jQuery:

var tmpl = '<div class="#{classname}">#{content}</div>';
var vals = {
    classname : 'my-class',
    content   : 'This is my content.'
};
var html = $.tmpl(tmpl, vals);
Andrew Hedges
fuente
1
Ordenado. Podría haber usado algo parecido en un gran proyecto hace unos meses.
Rodrick Chapman
Si. ¡Conciso y ordenado!
ajitweb
4

Puede agregar la plantilla HTML a su página en un div oculto y luego usar cloneNode y las instalaciones de consulta de su biblioteca favorita para completarla

/* 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*/})
León
fuente
3

Divulgación: soy el mantenedor de BOB.

Existe una biblioteca de JavaScript que facilita mucho este proceso llamada BOB .

Para su ejemplo específico:

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

Esto se puede generar con BOB mediante el siguiente código.

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

O con la sintaxis más corta

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

Esta biblioteca es bastante poderosa y se puede usar para crear estructuras muy complejas con inserción de datos (similar a d3), por ejemplo:

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>"

Actualmente, BOB no admite la inyección de datos en el DOM. Esto está en el todolista. Por ahora, simplemente puede usar la salida junto con JS normal o jQuery, y colocarla donde desee.

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());

Hice esta biblioteca porque no estaba satisfecho con ninguna de las alternativas como jquery y d3. El código es muy complicado y difícil de leer. Trabajar con BOB es, en mi opinión, que obviamente está sesgado, mucho más agradable.

BOB está disponible en Bower , por lo que puede obtenerlo ejecutándolo bower install BOB.

Automatico
fuente
2

¿Existe una buena práctica para esto? Puedo ver algunas formas de hacerlo:

  1. Concatenar cadenas
  2. Crear elementos
  3. Usa un complemento de plantillas
  4. Genere el html en el servidor, luego sirva a través de JSON.

1) Esta es una opción. Cree el html con JavaScript en el lado del cliente y luego inyéctelo en el DOM como un todo.

Tenga en cuenta que hay un paradigma detrás de este enfoque: el servidor genera solo datos y (en caso de interacción) recibe datos del cliente de forma asincrónica con las solicitudes AJAX. El código del lado del cliente funciona como una aplicación web JavaScript independiente.

La aplicación web puede funcionar, renderizar la interfaz, incluso sin que el servidor esté activo (por supuesto, no mostrará ningún dato ni ofrecerá ningún tipo de interacción).

Este paradigma se está adoptando a menudo últimamente, y se construyen marcos completos en torno a este enfoque (consulte backbone.js, por ejemplo).

2) Por razones de rendimiento, cuando sea posible, es mejor compilar el html en una cadena y luego inyectarlo como un todo en la página.

3) Esta es otra opción, además de adoptar un marco de aplicación web. Otros usuarios han publicado varios motores de plantillas disponibles. Tengo la impresión de que tienes las habilidades para evaluarlos y decidir si seguir este camino o no.

4) Otra opción. Pero sírvaselo como texto sin formato / html; ¿por qué JSON? No me gusta este enfoque porque mezcla PHP (el idioma de su servidor) con Html. Pero lo adopto a menudo como un compromiso razonable entre la opción 1 y la 4 .


Mi respuesta: ya está mirando en la dirección correcta.

Sugiero adoptar un enfoque entre 1 y 4 como lo hago yo. De lo contrario, adopte un marco web o un motor de plantillas.

Solo mi opinión basada en mi experiencia ...

Paolo
fuente