Digamos que queremos agregar algo a una página web después de la carga inicial. JavaScript nos brinda una variedad de herramientas. Quizás hayas usado algunos de ellos, como append
, appendChild
, insertAdjacentHTML
, o innerHTML
.
Lo difícil de agregar e insertar cosas con JavaScript no se trata tanto de las herramientas que ofrece, sino de cuál usar, cuándo usarlas y comprender cómo funciona cada una.
Intentemos aclarar las cosas.
Contexto superrápido
Puede resultar útil analizar un poco los antecedentes antes de saltar. En el nivel más simple, un sitio web es un archivo HTML descargado de un servidor a un navegador.
Su navegador convierte las etiquetas HTML dentro de su archivo HTML en un montón de objetos que se pueden manipular con JavaScript. Estos objetos construyen un árbol del Modelo de objetos de documento (DOM). Este árbol es una serie de objetos estructurados como relaciones padre-hijo.
En el lenguaje DOM, estos objetos se denominan nodos, o más específicamente, elementos HTML.
<!-- I'm the parent element -->
<div>
<!-- I'm a child element -->
<span>Hello</span>
</div>
En este ejemplo, el HTML span
elemento es el hijo de la div
elemento, que es el padre.
Y sé que algunos de estos términos son extraños y posiblemente confusos. Decimos “nodo”, pero otras veces podemos decir “elemento” u “objeto” en su lugar. Y, en algunos casos, se refieren a lo mismo, solo dependiendo de cuán específicos queramos ser.
Por ejemplo, un “elemento” es un tipo específico de “nodo”, al igual que una manzana es un tipo específico de fruta.
Podemos organizar estos términos desde los más generales hasta los más específicos: Objeto → Nodo → Elemento → Elemento HTML
Comprender estos elementos DOM es importante, ya que interactuaremos con ellos para agregar y adjuntar elementos con JavaScript después de la carga inicial de una página. De hecho, comencemos a trabajar en eso.
Configuración
Estos métodos de adición e inserción siguen principalmente este patrón:
Element.append_method_choice(stuff_to_append)
Una vez más, un elemento es simplemente un objeto en el árbol DOM que representa algo de HTML. Anteriormente, mencionamos que el propósito del árbol DOM es brindarnos una forma conveniente de interactuar con HTML usando JavaScript.
Entonces, ¿cómo usamos JavaScript para capturar un elemento HTML?
Consultando el DOM
Digamos que tenemos el siguiente fragmento de HTML:
<div id="example" class="group">
Hello World
</div>
Hay algunas formas comunes de consultar el DOM:
// Query a specific selector (could be class, ID, element type, or attribute):
const my_element1 = document.querySelector("https://css-tricks.com/comparing-methods-for-appending-and-inserting-with-javascript/#example")
// Query an element by its ID:
const my_element2 = document.getElementbyId('example')
// Query an element by its class:
const my_element3 = document.getElementsbyClassName('group')[0]
En este ejemplo, las tres líneas consultan lo mismo, pero lo buscan de diferentes maneras. Uno mira cualquiera de los selectores CSS del elemento; uno mira la identificación del artículo; y uno mira la clase del artículo.
Tenga en cuenta que el getElementbyClass
El método devuelve una matriz. Esto se debe a que es capaz de hacer coincidir varios elementos en el DOM y almacenar esas coincidencias en una matriz garantiza que se tengan en cuenta todos.
Qué podemos agregar e insertar
// Append Something
const my_element1 = document.querySelector("https://css-tricks.com/comparing-methods-for-appending-and-inserting-with-javascript/#example")
my_element1.append(something)
En este ejemplo, something
es un parámetro que representa las cosas que queremos agregar al final (es decir, agregar) al elemento coincidente.
No podemos simplemente agregar cualquier cosa vieja a cualquier objeto viejo. El append
El método solo nos permite agregar un nodo o texto sin formato a un elemento en el DOM. Pero algunos otros métodos también pueden agregar HTML a elementos DOM.
- Los nodos se crean con
document.createElement()
en JavaScript, o se seleccionan con uno de los métodos de consulta que vimos en la última sección. - El texto sin formato es, bueno, texto. Es texto sin formato en el sentido de que no lleva ninguna etiqueta HTML o formato. (p.ej
Hello
). - HTML también es texto pero, a diferencia del texto sin formato, de hecho se analiza como marcado cuando se agrega al DOM (p. Ej.
<div>Hello</div>
).
Podría ser útil mapear exactamente qué parámetros son compatibles con qué métodos:
Método | Nodo | Texto HTML | Texto |
---|---|---|---|
append |
sí | No | sí |
appendChild |
sí | No | No |
insertAdjacentHTML |
No | sí | Sí1 |
innerHTML 2 |
No | sí | sí |
1 Esto funciona, pero insertAdjacentText
es recomendado.
2 En lugar de tomar parámetros tradicionales, innerHTML
se usa como: element.innerHTML = 'HTML String'
Cómo elegir qué método usar
Bueno, realmente depende de lo que esté buscando agregar, sin mencionar ciertas peculiaridades del navegador para solucionar.
- Si tiene HTML existente que se envía a su JavaScript, probablemente sea más fácil trabajar con métodos que admitan HTML.
- Si está creando un nuevo HTML en JavasScript, crear un nodo con un marcado marcado puede ser engorroso, mientras que HTML es menos detallado.
- Si desea adjuntar detectores de eventos de inmediato, querrá trabajar con nodos porque llamamos
addEventListener
en nodos, no HTML. - Si todo lo que necesita es texto, cualquier método que admita parámetros de texto sin formato está bien.
- Si su HTML es potencialmente poco confiable (es decir, proviene de la entrada del usuario, digamos un comentario en una publicación de blog), entonces querrá tener cuidado al usar HTML, a menos que se haya desinfectado (es decir, se haya eliminado el código dañino).
- Si necesita ser compatible con Internet Explorer, utilice
append
está fuera de cuestión.
Ejemplo
Digamos que tenemos una aplicación de chat y queremos agregar un usuario, Dale, a una lista de amigos cuando inician sesión.
<!-- HTML Buddy List -->
<ul id="buddies">
<li><a>Alex</a></li>
<li><a>Barry</a></li>
<li><a>Clive</a></li>
<!-- Append next user here -->
</ul>
Así es como lo lograríamos usando cada uno de los métodos anteriores.
append
Necesitamos crear un objeto de nodo que se traduzca en <li><a>Dale</a></li>
.
const new_buddy = document.createElement('li')
const new_link = document.createElement('a')
const buddy_name = "Dale"
new_link.append(buddy_name) // Text param
new_buddy.append(new_link) // Node param
const list = document.querySelector('#buddies')
list.append(new_buddy) // Node param
Nuestra final append
coloca al nuevo usuario al final de la lista de amigos, justo antes del cierre </ul>
etiqueta. Si preferimos colocar al usuario al principio de la lista, podríamos usar el prepend
método en su lugar.
Es posible que haya notado que también pudimos usar append
para llenar nuestro <a>
etiqueta con texto como este:
const buddy_name = "Dale"
new_link.append(buddy_name) // Text param
Esto destaca la versatilidad de append
.
Y solo para llamarlo una vez más, append
no es compatible con Internet Explorer.
appendChild
appendChild
es otro método de JavaScript que tenemos para agregar cosas a elementos DOM. Es un poco limitado porque solo funciona con objetos de nodo, por lo que necesitaremos ayuda de textContent
(o innerText
) para nuestras necesidades de texto sin formato.
Tenga en cuenta que appendChild
, a diferencia de append
, es compatible con Internet Explorer.
const new_buddy = document.createElement('li')
const new_link = document.createElement('a')
const buddy_name = "Dale"
new_link.textContent = buddy_name
new_buddy.appendChild(new_link) // Node param
const list = document.querySelector('#buddies')
list.appendChild(new_buddy) // Node param
Antes de continuar, consideremos un ejemplo similar, pero con un marcado más pesado.
Digamos que el HTML que queríamos agregar no se veía como <li><a>Dale</a></li>
, sino más bien:
<li class="abc" data-tooltip="Click for Dale">
<a id="user_123" class="def" data-user="dale">
<img src="https://css-tricks.com/comparing-methods-for-appending-and-inserting-with-javascript/images/dale.jpg" alt="Profile Picture"/>
<span>Dale</span>
</a>
</li>
Nuestro JavaScript se vería así:
const buddy_name = "Dale"
const new_buddy = document.createElement('li')
new_buddy.className="abc"
new_buddy.setAttribute('data-tooltip', `Click for ${buddy_name}`)
const new_link = document.createElement('a')
new_link.id = 'user_123'
new_link.className="def"
new_link.setAttribute('data-user', buddy_name)
const new_profile_img = document.createElement('img')
new_profile_img.src="https://css-tricks.com/comparing-methods-for-appending-and-inserting-with-javascript/images/dale.jpg"
new_profile_img.alt="Profile Picture"
const new_buddy_span = document.createElement('span')
new_buddy_span.textContent = buddy_name
new_link.appendChild(new_profile_img) // Node param
new_link.appendChild(new_buddy_span) // Node param
new_buddy.appendChild(new_link) // Node param
const list = document.querySelector('#buddies')
list.appendChild(new_buddy) // Node param
No es necesario seguir todo el JavaScript anterior; el punto es que crear grandes cantidades de HTML en JavaScript puede volverse bastante engorroso. Y no hay forma de evitar esto si usamos append
o appendChild
.
En este escenario de marcado pesado, sería bueno simplemente escribir nuestro HTML como una cadena, en lugar de usar un montón de métodos JavaScript …
insertAdjacentHTML
insertAdjacentHTML
es como append
ya que también es capaz de agregar cosas a los elementos DOM. Sin embargo, una diferencia es que insertAdjacentHTML
inserta ese material en una posición específica en relación con el elemento coincidente.
Y da la casualidad de que funciona con HTML. Eso significa que podemos insertar HTML real en un elemento DOM y señalar exactamente dónde lo queremos con cuatro posiciones diferentes:
<!-- beforebegin -->
<div id="example" class="group">
<!-- afterbegin -->
Hello World
<!-- beforeend -->
</div>
<!-- afterend -->
Entonces, podemos replicar la misma idea de “agregar” nuestro HTML insertándolo en el beforeend
posición del #buddies
selector:
const buddy_name = "Dale"
const new_buddy = `<li><a>${buddy_name}</a></li>`
const list = document.querySelector('#buddies')
list.insertAdjacentHTML('beforeend', new_buddy)
Recuerde las preocupaciones de seguridad que mencionamos anteriormente. Nosotros nunca queremos insertar HTML que ha sido enviado por un usuario final, ya que nos expondríamos a vulnerabilidades de secuencias de comandos entre sitios.
innerHTML
innerHTML
es otro método para insertar cosas. Dicho esto, no se recomienda para insertar, como veremos.
Aquí está nuestra consulta y el HTML que queremos insertar:
const buddy_name = "Dale"
const new_buddy = `<li><a>${buddy_name}</a></li>`
const list = document.querySelector('#buddies')
list.innerHTML += new_buddy
Inicialmente, esto parece funcionar. Nuestra lista de amigos actualizada se ve así en el DOM:
<ul id="buddies">
<li><a>Alex</a></li>
<li><a>Barry</a></li>
<li><a>Clive</a></li>
<li><a>Dale</a></li>
</ul>
¡Eso es lo que queremos! Pero hay una restricción al usar innerHTML
que nos impide usar detectores de eventos en cualquier elemento dentro de #buddies
debido a la naturaleza de +=
en list.innerHTML += new_buddy
.
Verás, A += B
se comporta igual que A = A + B
. En este caso, A
es nuestro HTML existente y B
es lo que le estamos insertando. El problema es que esto da como resultado una copia del HTML existente con el HTML adicional insertado. Y los oyentes de eventos no pueden escuchar copias. Eso significa que si queremos escuchar un evento de clic en cualquiera de los <a>
etiquetas en la lista de amigos, vamos a perder esa capacidad con innerHTML
.
Entonces, solo una palabra de advertencia.
Manifestación
Aquí hay una demostración que reúne todos los métodos que hemos cubierto. Al hacer clic en el botón de cada método, se inserta “Dale” como un elemento en la lista de amigos.
Continúe y abra DevTools mientras lo hace y vea cómo se agrega el nuevo elemento de la lista al DOM.
Resumen
Aquí hay una descripción general de dónde nos encontramos cuando agregamos e insertamos cosas en el DOM. Considérelo una hoja de trucos para cuando necesite ayuda para determinar qué método utilizar.
Método | Nodo | Texto HTML | Texto | ¿Explorador de Internet? | Oyentes de eventos | ¿Seguro? | Plantillas HTML |
---|---|---|---|---|---|---|---|
append |
sí | No | sí | No | Conservas | sí | Medio |
appendChild |
sí | No | No | sí | Conservas | sí | Medio |
insertAdjacentHTML |
No | sí | Sí1 | sí | Conservas | Cuidadoso | Fácil |
innerHTML 2 |
No | sí | sí | sí | Pierde | Cuidadoso | Fácil |
1 Esto funciona, pero insertAdjacentText
es recomendado.
2 En lugar de tomar parámetros tradicionales, innerHTML
se usa como: element.innerHTML = 'HTML String'
Si tuviera que condensar todo eso en algunas recomendaciones:
- Utilizando
innerHTML
para agregar no se recomienda ya que elimina los detectores de eventos. append
funciona bien si le gusta la flexibilidad de trabajar con elementos de nodo o texto sin formato, y no necesita ser compatible con Internet Explorer.appendChild
funciona bien si desea (o necesita) trabajar con elementos de nodo y desea una cobertura completa del navegador.insertAdjacentHTML
es bueno si necesita generar HTML y desea un control más específico sobre dónde se coloca en el DOM.
Excavar más hondo
Los métodos discutidos anteriormente se usan comúnmente y deben cubrir la mayoría de sus casos de uso.
Dicho esto, existen algunos métodos adicionales de adición / inserción, si tiene curiosidad:
- antes de
- después
- insertBefore
- insertar elemento adyacente
Último pensamiento y un enchufe rápido 🙂
Esta publicación se inspiró en problemas reales que encontré recientemente al crear una aplicación de chat. Como puede imaginar, una aplicación de chat se basa en una gran cantidad de anexos / inserciones: personas que se conectan, mensajes nuevos, notificaciones, etc.
Esa aplicación de chat se llama Bounce. Es un chat de aprendizaje de igual a igual. Suponiendo que es un desarrollador de JavaScript (entre otras cosas), ¡probablemente tenga algo que enseñar! Y puedes ganar algo de dinero extra.
Si tiene curiosidad, aquí hay un enlace a la página de inicio o mi perfil en Bounce. ¡Salud!