Estoy creando una aplicación web utilizando JS puro sin marcos. La aplicación es como una aplicación tipo tablero que extraerá datos de una API y los mostrará usando HTML. Me gustaría crear componentes HTML reutilizables en JS que pueda mantener y usar fácilmente en toda mi aplicación.
Mi pregunta es si hay una mejor manera de generar elementos HTML dinámicos en JS.
El siguiente código a continuación es una explicación de mi forma actual de generar elementos dinámicos.
Actualmente, mi configuración es tener una etiqueta div HTML con una identificación. Esta etiqueta es donde apuntaría en mi JS y le agregaría elementos generados dinámicamente.
<div id="user-anchor"></div>
Apunte a esta identificación y agréguele elementos con la función drawUserInformation()
. Esta función toma una matriz de objetos, crea los elementos dinámicos y los agrega al ancla div.
/* * @param {array} users - array of user objects */ function drawUserInformation(users) { let userAnchor = document.getElementById("user-anchor"); for (let user of users) { let userCard = createUserCard(user); userAnchor.append(userCard); } }
Para crear los elementos HTML dinámicos, se llama a la función createUserCard()
. Esta función toma un objeto que representa a un usuario y devuelve un objeto Element. He simplificado la cantidad de datos que se muestran para este ejemplo.
function createUserCard(user) { let userCardEle = document.createElement("div"); userCardEle.innerHTML = ` <h5 class="card-title">User</h5> <dl class="row"> <dt class="col-sm-3">Name</dt> <dd class="col-sm-9">${user.first_name} ${user.last_name}</dd"> <dt class="col-sm-3">Score</dt> <dd class="col-sm-9">${user.score}</dd"> </dl> `; return userCardEle; }
En mi función createUserCard()
, ¿hay una mejor manera de generar el HTML para este componente sin usar innerHTML
? En mi aplicación actual, tengo varios de estos tipos de funciones para varios componentes y todos innerHTML
. Las cadenas que escribo son muy largas (mucho más largas que este ejemplo) y no tienen ninguna pelusa de HTML, por lo que es mucho más difícil de mantener y depurar.
Puede utilizar el elemento de template
.
Para crear una instancia del elemento de template
, use tmplElem.content.cloneNode(true)
.
function createUserCard(user) { let userCardEle = userCard.content.cloneNode(true); let elems = byName(userCardEle); elems.first_name.innerText = user.first_name; elems.last_name.innerText = user.last_name; elems.score.innerText = user.score; return userCardEle; } function byName (elem) { return new Proxy({}, { get (_, prop) { return elem.querySelector(`[name=${prop}]`); } }); } // Test document.body.appendChild(createUserCard({first_name: "John", last_name: "Smith", score: 1e+5}));
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous"> <template id=userCard> <div> <h5 class="card-title">User</h5> <dl class="row"> <dt class="col-sm-3">Name</dt> <dd class="col-sm-9"> <span name=first_name></span> <span name=last_name></span> </dd> <dt class="col-sm-3">Score</dt> <dd class="col-sm-9"><span name=score></span></dd> </dl> </div> </template>
Otro enfoque podría ser facilitar el acceso al DOM con una función que permita la creación de elementos anidados similares a jQuery:
// Generic DOM element creator function Elem(type, attr, ...children) { let elem = Object.assign(document.createElement(type), attr); for (let child of children) { elem.appendChild(Object(child) === child ? child : document.createTextNode(child)); } return elem; } function drawUserInformation(users) { let userAnchor = document.getElementById("user-anchor"); for (let user of users) { let userCard = createUserCard(user); userAnchor.append(userCard); } } function createUserCard(user) { return Elem("div", {}, Elem("h5", { className: "card-title" }, "User"), Elem("dl", { className: "row" }, Elem("dt", { className: "col-sm-3" }, "Name"), Elem("dd", { className: "col-sm-9" }, user.first_name + " " + user.last_name), Elem("dt", { className: "col-sm-3" }, "Score"), Elem("dd", { className: "col-sm-9" }, user.score), ) ); } let data = [ { first_name: "Nafi", last_name: "Thiam", score: 6791 }, { first_name: "Mutaz Essa", last_name: "Barshim", score: 237 }, { first_name: "Gianmarco", last_name: "Tamberi", score: 237 }, ] drawUserInformation(data);
<div id="user-anchor"></div>