2010-02-07 12 views
48

¿Existe una mejor práctica general para crear elementos HTML algo complejos en jQuery? Lo intenté de diferentes maneras.jQuery: mejor práctica para crear fragmentos complejos de HTML

Primero trató de usar createElement y encadenar un montón de los que junto con AppendTo y similares:

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

Esto puede ser duro ya appendTo quiere añadir a cada elemento que cumpla con lo que todo necesita su propio nombre lo contrario se termina subiendo repetidamente por todo el lugar.

Luego he intentado crear una matriz y unirse juntos:

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

Esto parece funcionar bastante bien, aunque en IE cuando yo pondría una alerta ($ (badgeFragment) .text()) por lo general regresó vacío (Esto fue parte de la depuración de un problema más grande). Obviamente estoy un poco nuevo en jQuery (E incluso Javascript en realidad) por lo que para tratar de asegurarse de que esto no era el problema He intentado un tercer método - El gigante de concatenación de cadenas:

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>'; 

es uno de estos métodos generalmente considerado mejor que los demás? No soy muy bueno con los diferentes perfiladores, así que no estoy seguro de cómo verificarlo yo mismo. También está la cuestión de si todos estos métodos cumplen o no con los navegadores cruzados.

+0

alerta en IE encontró nada porque ".text()" no conseguir todos los contenidos de su sub-árbol DOM. Pruebe $ (badgeFragment) .html() – Pointy

Respuesta

56

con jQuery 1.4, puede crear elementos HTML así:

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

Aquí es a link to the documentation.

No estoy seguro de que este enfoque sea más rápido que usar la función html() de jQuery. O más rápido que omitir jQuery todos juntos y usar la propiedad innerHTML en un elemento. Pero en lo que respecta a la legibilidad; el enfoque jQuery es mi favorito. Y en la mayoría de los casos, la ganancia de rendimiento de usar innerHTML es marginal.

+1

Se perdió una coma después del primer argumento de jQuery (ps – Spidey

+1

Gracias Spidey. Respuesta actualizada – roosteronacid

+1

@roosteronacid dependiendo de [jQuery docs] (http://api.jquery.com/jQuery/) 'El nombre" clase "debe citarse en el objeto ya que es una palabra reservada de JavaScript'. – Pierre

3

Personalmente creo que es más importante que el código sea legible y editable que el rendimiento. Cualquiera que le resulte más fácil de ver y realizar cambios sin romperlo debe ser el que elija.

8

Usted no tiene que llamar document.createElement:

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

Hay todo tipo de herramientas útiles en jQuery para extender/ammending el DOM. Mire los diversos métodos de "envoltura" por ejemplo.

Otra posibilidad: para grandes cantidades de contenido nuevo, es mejor que su servidor los prepare (usando el sistema de plantillas del lado del servidor, sea lo que sea) y obtenerlos con $.load() o algún otro enfoque ajax .

8

Me inclinaría a mirar uno de los motores de plantillas para jQuery como jQote

+1

+1. o jsRender, o guión bajo: hay muchas opciones, y son mucho mejores esp porque Javscript no admite cadenas de varias líneas y funciones de reemplazo de parámetros tipo sprintf – msanjay

7

John Resig (creador de jQuery) sugirió el uso de este método de plantillas en 2008. Se realidad tiene algunas características muy interesantes:

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

luego recuperarla usando ...

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

Ver aquí para más detalles:
http://ejohn.org/blog/javascript-micro-templating/

+2

Hoy en día, puede ir un paso más simple y más hermoso y usar [ICanHaz] (http://icanhazjs.com/), que combina este enfoque con el sistema de plantillas de bigote para plantillas más bonitas y creación de elementos de una sola línea. –

+0

ICanHaz se ve genial, @MarkAmery, pero solo desperdició un par de horas de mi tiempo antes de que finalmente descubriera que ni la plantilla ni el bigote no maneja muy bien ciertos caracteres, como la barra invertida \. No puedo permitirme esta pérdida de tiempo! – ErikE

+0

@ErikE Ouch. Estoy bastante sorprendido de que una biblioteca con tanta actividad como icanhaz se rompa de manera significativa. ¿Hay alguna posibilidad de que pueda proporcionar un caso de demostración mínimo en jsfiddle? Podría tener una jugada y ver si puedo arreglar el error. –

0

La forma en que estoy haciendo se muestra abajo. No estoy seguro de si deberías crear tantos divs, pero funcionó bastante bien conmigo.

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

Hola @marcelosalloum, desde mi experiencia, esto es absolutamente doloroso cuando alguien dice que necesito que agregue ahora a su código ...Sí, funciona, y no puedo comentar sobre el rendimiento, pero es muy doloroso mantener ... – Ads

+0

Si su objetivo es simplemente crear una plantilla y luego completarla con algunos datos, personalmente me gusta hacer un ' mostrar: ninguno; 'contenedor para mis elementos de plantilla, buscarlos en variables javascript utilizando getElementById() o jQuery, clonarlo, y luego manejar los datos llenándome a mi mismo (.textContent = val/.text (val), .setAttribute (attr, val) /. attr (attr, val)) porque es más fácil hacerlo yo solo que preocuparme si alguna biblioteca de plantillas defectuosa hará su trabajo correctamente y mucho más porque sé exactamente lo que quiero hacer con la plantilla. –

2

Es más legible y fácil de mantener si el código JavaScript se asemeja a la estructura de etiquetas HTML. Puede ir a la ruta jQuery oficial usando $ ('div', {'clase': 'etc'}) ...

Aquí hay un enfoque ligeramente diferente usando una función $$ para hacer que cada elemento sea un objeto jQuery editable . Debería ser bastante rápido ya que no está teniendo lugar ningún análisis html.

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

Esto hace que el enfoque más flexible y se puede añadir controladores de eventos, datos, etc. a los objetos jQuery anidadas utilizando el encadenamiento con bastante facilidad, por ejemplo,

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

El código es más legible que si se fuera a utilizar el método oficial de jQuery de hacerlo con llamadas separadas a .Append(), .text(), html(), etc., o mediante la alimentación del jQuery $ una cadena HTML concatenada.

Tipo de referencia $$:

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; 
} 
Cuestiones relacionadas