Existe uma prática recomendada para gerar html com javascript

103

Estou chamando um serviço da web que retorna uma matriz de objetos em JSON. Quero pegar esses objetos e preencher um div com HTML. Digamos que cada objeto contenha um url e um nome.

Se eu quisesse gerar o seguinte HTML para cada objeto:

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

Existe uma prática recomendada para isso? Posso ver algumas maneiras de fazer isso:

  1. Cordas concatenadas
  2. Crie elementos
  3. Use um plugin de templates
  4. Gere o html no servidor e depois sirva via JSON.
ckarbass
fonte
1
Você também pode verificar o sublinhado js: documentcloud.github.com/underscore/#template Ele funciona muito bem com backbone.js
luacassus
A escolha de 1 a 4: depende de quanto conteúdo deve ser injetado (prefira 4 para maior) quantas partes diferentes de html precisarão ser anexadas no total (3 ou 4). com o que o sb está familiarizado. (Influência no tempo de desenvolvimento). Se você não conhece nenhuma ferramenta é apenas um pequeno modal que será injetado uma vez que eu não conheço uma maneira melhor do que o puro js de fazê-lo (1-2)
partizanos

Respostas:

68

As opções 1 e 2 serão suas opções diretas mais imediatas, no entanto, para ambas as opções, você sentirá o impacto no desempenho e na manutenção ao construir strings ou criar objetos DOM.

A modelagem não é tão imatura, e você está vendo uma janela pop-up na maioria dos principais frameworks Javascript.

Aqui está um exemplo no JQuery Template Plugin que irá economizar o impacto de desempenho e é muito, muito simples:

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

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

Eu digo ir pelo caminho legal (e com melhor desempenho, mais sustentável) e usar modelos.

Jim Fiorato
fonte
13
Os modelos JQuery parecem estar mortos, consulte stackoverflow.com/questions/7911732/…
James McMahon
4
@Jim Fiorato: o link está morto: s
Adrien Be
2
Link está morto, como Adrien aponta. Sugiro que você atualize sua resposta para incluir: Mustache.js
Sr. Polywhirl
1
Alguém pode explicar, por que uma resposta baseada em jQuery é a mais aceita? Duvido que esta seja a melhor prática!
WoIIe
1
@WoIIe Ainda pior, o plugin jQuery está morto, então esta resposta está desatualizada.
Franklin Yu
13

Se você absolutamente tiver que concatenar strings, em vez do normal:

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

use uma matriz temporária:

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

Usar matrizes é muito mais rápido, especialmente no IE. Eu fiz alguns testes com strings há algum tempo com o IE7, Opera e FF. O Opera demorou apenas 0,4s para realizar o teste, mas o IE7 não terminou depois de 20 MINUTOS !!!! (Não, não estou brincando.) Com o array o IE foi muito rápido.

alguns
fonte
Troquei de navegador há muito tempo, então não sofro tanto. O IE era um navegador horrível, mas está melhorando. Mas duvido que algum dia voltarei.
cerca de
1
O desempenho lento visto no primeiro método é provável porque a string de resultado deve ser realocada 200 vezes e as alocações de memória podem ser lentas. Depois de duas iterações, você tem "testes e testes". Depois de três iterações, essa string é descartada e a memória com espaço suficiente para "testingtestingtesting" é alocada. E assim por diante 200 vezes com comprimento crescente gradualmente. No entanto, s.join () aloca uma nova string como resultado que é longa o suficiente para caber todas elas e, em seguida, copia em cada uma. Uma alocação, muito mais rápida.
EricP
1
@JoeCoder, concordou, é um algoritmo Shlemiel, o Pintor. joelonsoftware.com/articles/fog0000000319.html
Jodrell
8

Qualquer uma das duas primeiras opções é comum e aceitável.

Vou dar exemplos de cada um no Prototype .

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

Abordagem # 1:

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

Abordagem # 2:

var div = new Element('div');
div.insert( new Element('img', { src: json.src }) );
div.insert(" " + json.name);
$('container').insert(div); // inserts at bottom
savetheclocktower
fonte
Construir a geração do HTML explicitamente com strings em vez de elementos DOM tem mais desempenho (assumindo que a concatenação de string não é um problema real) e legível.
Rodrick Chapman
No IE, a concatenação de strings sempre é um problema. Em vez disso, use uma matriz.
cerca de
7

Talvez uma abordagem mais moderna seja usar uma linguagem de modelos, como Mustache , que tem implementações em muitas linguagens, incluindo javascript. Por exemplo:

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

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

Você ainda obtém um benefício adicional - pode reutilizar os mesmos modelos em outros lugares, como o servidor.

Se precisar de modelos mais complicados (instruções if, loops, etc.), você pode usar o Handlebars, que tem mais recursos e é compatível com o Mustache.

Tzach
fonte
6

Aqui está um exemplo, usando meu plug-in Simple Templates 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
fonte
1
Arrumado. Eu poderia ter usado algo parecido em um grande projeto há alguns meses.
Rodrick Chapman
Sim. Conciso e elegante!
ajitweb
4

Você pode adicionar o modelo HTML à sua página em um div oculto e, em seguida, usar cloneNode e os recursos de consulta da sua biblioteca favorita para preenchê-lo

/* 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*/})
Leo
fonte
3

Divulgação: Eu sou o mantenedor do BOB.

Existe uma biblioteca javascript que torna esse processo muito mais fácil, chamada BOB .

Para seu exemplo específico:

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

Isso pode ser gerado com BOB pelo código a seguir.

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

Ou com a sintaxe mais curta

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

Esta biblioteca é bastante poderosa e pode ser usada para criar estruturas muito complexas com inserção de dados (semelhante ao d3), por exemplo:

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

O BOB atualmente não suporta a injeção de dados no DOM. Isso está no todolist. Por enquanto, você pode simplesmente usar a saída junto com JS normal ou jQuery e colocá-la onde quiser.

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

Fiz esta biblioteca porque não fiquei satisfeito com nenhuma das alternativas como jquery e d3. O código é muito complicado e difícil de ler. Trabalhar com o BOB é, na minha opinião, o que obviamente é tendencioso, muito mais agradável.

O BOB está disponível no Bower , então você pode obtê-lo executando bower install BOB.

Automatico
fonte
2

Existe uma prática recomendada para isso? Posso ver algumas maneiras de fazer isso:

  1. Cordas concatenadas
  2. Crie elementos
  3. Use um plugin de templates
  4. Gere o html no servidor e depois sirva via JSON.

1) Esta é uma opção. Construa o html com JavaScript no lado do cliente e, em seguida, injete-o no DOM como um todo.

Observe que há um paradigma por trás dessa abordagem: o servidor emite apenas dados e (no caso de interação) recebe dados do cliente assincronamente com solicitações AJAX. O código do lado do cliente opera como um aplicativo da web JavaScript autônomo.

O aplicativo da web pode operar, renderizar a interface, mesmo sem o servidor estar ativo (é claro que não exibirá nenhum dado ou oferecerá qualquer tipo de interação).

Esse paradigma está sendo adotado com frequência ultimamente, e frameworks inteiros são construídos em torno dessa abordagem (consulte backbone.js, por exemplo).

2) Por motivos de desempenho, quando possível, é melhor construir o html em uma string e, em seguida, injetá-lo como um todo na página.

3) Essa é outra opção, além de adotar um framework de Web Application. Outros usuários postaram vários mecanismos de modelos disponíveis. Tenho a impressão de que você tem competência para avaliá-los e decidir se segue ou não por esse caminho.

4) Outra opção. Mas sirva como um texto simples / html; porque JSON? Não gosto dessa abordagem porque mistura PHP (sua linguagem de servidor) com Html. Mas eu adoto isso frequentemente como um meio-termo razoável entre as opções 1 e 4 .


Minha resposta: você já está olhando na direção certa.

Sugiro adotar uma abordagem entre 1 e 4, como eu. Caso contrário, adote uma estrutura da web ou mecanismo de modelagem.

Apenas minha opinião baseada na minha experiência ...

Paolo
fonte