2010-02-07 8 views
48

Esiste una best practice generale per la creazione di elementi HTML complessi in jQuery? Ho provato diversi modi.jQuery - Best practice per la creazione di complessi frammenti HTML

Per prima cosa ho provato ad utilizzare createElement e concatenamento un sacco di coloro che insieme con appendTo e simili:

var badge = $(document.createElement("div")).attr("class", "wrapper1").appendTo("body"); 
$(document.createElement("div")).attr("class", "wrapper2").appendTo(".wrapper1"); 
$(document.createElement("table")).attr("class", "badgeBody").appendTo(".wrapper2"); 
$(document.createElement("tr")).attr("class", "row1").appendTo(".badgeBody"); 
$(document.createElement("td")).appendTo(".row1"); 
$(document.createElement("span")).attr("class", "badgeUnlocked").text("UNLOCKED! ").appendTo("td"); 
$(document.createElement("td")).attr("class", "badgeTitleText").appendTo(".row1"); 
$(document.createElement("span")).attr("class", "badgeTitle").text(name).appendTo(".badgeTitleText"); 
$(document.createElement("tr")).attr("class", "row2").appendTo(".badgeBody"); 
$(document.createElement("td")).appendTo(".row2"); 
$(document.createElement("img")).attr("src", imgUrl).appendTo(".row2 td"); 
$(document.createElement("td")).attr("class", "badgeText").appendTo(".row2"); 
$(document.createElement("span")).attr("class", "badgeDescription").text(description).appendTo(".badgeText"); 

Questo può essere agitato dal appendTo vuole aggiungere ad ogni elemento corrispondenti in modo tutto deve il proprio nome altrimenti va a finire per essere aggiunto ripetutamente dappertutto.

Poi ho cercato di creare un array e unendo insieme:

var badgeFragment = [ 
'<div><div id="'+ closeId+'" class="closeTab">X</div>', 
'<div id="'+ badgeId+'" class="wrapper1">', 
'<div class="wrapper2">', 
'<div class="badgeBody">', 
'<div class="badgeImage">', 
'<img src="'+ imgUrl +'">', 
'</div>', 
'<div class="badgeContents">', 
'<div class="badgeUnlocked">ACHIEVEMENT UNLOCKED: </div>', 
'<div class="badgeTitle">'+ name +'</div>', 
'<div id="'+ textId+'" class="badgeDescription">'+ description +'</div>', 
'</div>', 
'<div style="clear:both"></div>', 
'</div></div></div></div></div>', 
] 

badgeFragment = $(badgeFragment.join('')); 

Questo sembra funzionare abbastanza bene, anche se in IE quando avrei messo un avviso ($ (badgeFragment) .text()) di solito è tornato vuoto (Questo era parte del debug di un problema più grande). Sono ovviamente un po 'nuova per jQuery (e anche Javascript realmente) in modo da provare e assicurarsi che questo non era il problema che ho provato un terzo metodo - gigante concatenazione di stringhe:

var badgeFragment = 
'<div><div id="'+ closeId+'" class="closeTab">X</div>' + 
'<div id="'+ badgeId+'" class="wrapper1">' + 
'<div class="wrapper2">' + 
'<div class="badgeBody">' + 
'<div class="badgeImage">' + 
'<img src="C:/Users/Ryan/Documents/icons/crystal_project/64x64/apps/chat.png">' + 
'</div>' + 
'<div class="badgeContents">' + 
'<div class="badgeUnlocked">ACHIEVEMENT UNLOCKED: </div>' + 
'<div class="badgeTitle">test</div>' + 
'<div id="'+ textId+'" class="badgeDescription">test</div>' + 
'</div>' + 
'<div style="clear:both"></div>' + 
'</div></div></div></div></div>'; 

è uno di questi metodi in generale considerato migliore degli altri? Non sono molto bravo con i vari profiler, quindi non sono sicuro di come verificarlo da solo. C'è anche la questione di sapere se tutti questi metodi sono compatibili con il cross browser.

+0

tua allerta in IE si avvicinò vuoto perchè ".text()" non ottenere tutti i contenuti del tuo sottostruttura DOM. Prova $ (badgeFragment) .html() – Pointy

risposta

56

con jQuery 1.4, è possibile creare elementi HTML in questo modo:

// create an element with an object literal, defining properties 
var e = $("<a />", { 
    href: "#", 
    "class": "a-class another-class", // you need to quote "class" since it's a reserved keyword 
    title: "..." 
}); 

// add the element to the body 
$("body").append(e); 

Ecco a link to the documentation.

Non sono sicuro che questo approccio sia più veloce rispetto all'utilizzo della funzione html() di jQuery. O più veloce di saltare jQuery tutti insieme e utilizzare la proprietà innerHTML su un elemento. Ma per quanto riguarda la leggibilità va; l'approccio jQuery è il mio preferito. E nella maggior parte dei casi il guadagno di prestazioni nell'uso di innerHTML è marginale.

+1

Hai perso una virgola dopo il primo argomento di jQuery ($). – Spidey

+1

Grazie Spidey. Risposta aggiornata – roosteronacid

+1

@roosteronacid a seconda dei [documenti jQuery] (http://api.jquery.com/jQuery/) 'Il nome" classe "deve essere riportato nell'oggetto poiché è una parola riservata JavaScript'. – Pierre

3

Personalmente penso che sia più importante che il codice sia leggibile e modificabile di performante. Chiunque trovi più facile guardare e apportare modifiche senza romperlo dovrebbe essere quello che scegli.

8

Non è necessario chiamare document.createElement:

$('#existingContainer').append(
    $('<div/>') 
    .attr("id", "newDiv1") 
    .addClass("newDiv purple bloated") 
    .append("<span/>") 
     .text("hello world") 
); 

Ci sono tutti i tipi di strumenti utili a jQuery per l'estensione/ammending DOM. Guarda i vari metodi "avvolgere" per esempio.

Un'altra possibilità: per grandi quantità di nuovi contenuti, potrebbe essere meglio avere i server che li preparano (utilizzando il sistema di templating sul lato server, qualunque cosa sia per voi) e recuperare quelli con $.load() o qualche altro approccio ajax .

8

sarei propenso a guardare uno dei motori di template per jQuery come jQote

+1

+1. o jsRender, o underscore - ci sono un sacco di scelte, e sono molto meglio perché Javscript non supporta le stringhe multi-linea e il tipo sprintf delle funzioni di sostituzione dei parametri – msanjay

7

John Resig (creatore di jQuery) ha suggerito di utilizzare questo metodo di template nel 2008. E 'in realtà ha alcune caratteristiche piuttosto interessanti:

<script type="text/html" id="item_tmpl"> 

    <div id="<%=id%>" class="<%=(i % 2 == 1 ? " even" : "")%>"> 
    <div class="grid_1 alpha right"> 
     <img class="righted" src="<%=profile_image_url%>"/> 
    </div> 
    <div class="grid_6 omega contents"> 
     <p><b><a href="/<%=from_user%>"><%=from_user%></a>:</b> <%=text%></p> 
    </div> 
    </div> 

</script> 

quindi il recupero utilizzando ...

var results = document.getElementById("results"); 
results.innerHTML = tmpl("item_tmpl", dataObject); 

Vedi qui per maggiori dettagli:
http://ejohn.org/blog/javascript-micro-templating/

+2

Al giorno d'oggi, puoi fare un passo più semplice e più bello e usare [ICanHaz] (http://icanhazjs.com/), che combina questo approccio con il sistema di template Mustache per modelli più carini e creazione di elementi a una linea. –

+0

ICanHaz sembra fantastico, @MarkAmery, ma ha sprecato un paio di ore del mio tempo prima che finalmente ho capito che o il template di Baffo non gestisce molto bene certi caratteri, come il backslash \. Non posso permettermi questa perdita di tempo! – ErikE

+0

@ErikE Ouch. Sono piuttosto sorpreso che una libreria con la stessa attività di icanhaz si rompa in modo significativo. Qualche possibilità che tu possa fornire un caso demo minimale in un jsfiddle? Potrei avere un gioco e vedere se riesco a correggere il bug. –

0

Il modo in cui sto facendo è mostrato sotto. Non sono sicuro che dovresti creare così tanti div, ma ha funzionato molto bene con me.

var div1 = $('<div class="colwrap_fof"></div>');  //THE COMPLEX DIV ITSELF 
var div2 = $('<div class="homeimg"></div>');     
var div21 = $('<div id="backImageDiv'+fof_index+'" class="backDiv"></div>'); 
var div22 = $('<div id="frontImageDiv'+fof_index+'" class="frontDiv"></div>'); 
div2.append(div21); 
div2.append(div22); 
div1.append(div2); 
$("#df_background").append(div1);  // ADDING the complex div to the right place  

Cheers,

+2

Ciao @marcelosalloum, dalla mia esperienza questo è assolutamente doloroso quando qualcuno dice che ho bisogno che tu ora aggiunga al tuo codice ..Sì, funziona, e non posso commentare le prestazioni, ma è molto doloroso da mantenere .. – Ads

+0

Se il tuo obiettivo è semplicemente creare un modello e poi riempirlo con alcuni dati, personalmente mi piace solo fare un ' display: none; 'contenitore per i miei elementi del modello, li preleva in variabili javascript usando getElementById() o jQuery, clonalo, quindi gestisco i dati riempiendo me stesso (.textContent = val/.text (val), .setAttribute (attr, val) /. attr (attr, val)) perché è più facile farlo da solo che preoccuparsi che una libreria scadente per i modelli faccia il suo lavoro correttamente e molto più performante perché so esattamente cosa voglio fare con il modello. –

2

E 'più leggibile e gestibile se il codice JavaScript assomiglia alla struttura dei tag HTML. Puoi usare il percorso jQuery ufficiale usando $ ('div', {'classe': 'etc'}) ...

Ecco un approccio leggermente diverso usando una funzione $$ per rendere ogni elemento un oggetto jQuery modificabile . Dovrebbe essere piuttosto veloce in quanto non vi è alcuna analisi html in atto.

$$('div', {'id':'container'}, 
    $$('div', {'id':'my_div'}, 
     $$('h1',{'class':'my_header'}, 
      $$('a',{'href':'/test/', 'class':'my_a_class'}, 'teststring')))); 

Questo rende l'approccio più flessibile e si può aggiungere gestori di eventi, dati ecc per gli oggetti nidificati jQuery utilizzando il concatenamento abbastanza facilmente per esempio

$$('div', {'id':'container'}, 
    $$('div', {'id':'my_div'}, 
     $$('h1',{'class':'my_header'}, 
      $$('a', { 'href': '/test/', 'class': 'my_a_class' }, 'teststring') 
     ).click(function() { alert('clicking on the header'); }) 
    ).data('data for the div') 
).hide(); 

il codice è più leggibile rispetto se si dovesse utilizzare l'approccio ufficiale jQuery di farlo con chiamate separate per .Append(), .text(), .html(), ecc o alimentando il jQuery $ una stringa HTML concatenata.

funzione Riferimento $$:

function $$(tagName, attrTextOrElems) { 
    // Get the arguments coming after the params argument 
    var children = []; 
    for (var _i = 0; _i < (arguments.length - 2) ; _i++) { 
     children[_i] = arguments[_i + 2]; 
    } 

    // Quick way of creating a javascript element without JQuery parsing a string and creating the element 
    var elem = document.createElement(tagName); 
    var $elem = $(elem); 

    // Add any text, nested jQuery elements or attributes 
    if (attrTextOrElems) { 
     if (typeof attrTextOrElems === "string") { // text 
      var text = document.createTextNode(attrTextOrElems); 
      elem.appendChild(text); 
     } 
     else if (attrTextOrElems instanceof jQuery) { // JQuery elem 
      $elem.append(attrTextOrElems); 
     } 
     else // Otherwise an object specifying attributes e.g. { 'class': 'someClass' } 
     { 
      for (var key in attrTextOrElems) { 
       var val = attrTextOrElems[key]; 
       if (val) { 
        elem.setAttribute(key, val); 
       } 
      } 
     } 
    } 

    // Add any further child elements or text  
    if (children) { 
     for (var i = 0; i < children.length; i++) { 
      var child = children[i]; 
      if (typeof child === "string") { // text 
       var text = document.createTextNode(child); 
       elem.appendChild(text); 
      } else { // JQuery elem 
       $elem.append(child); 
      } 
     } 
    } 
    return $elem; 
} 
Problemi correlati