- Notifications
You must be signed in to change notification settings - Fork230
Mutation observer#337
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Merged
Uh oh!
There was an error while loading.Please reload this page.
Merged
Changes fromall commits
Commits
Show all changes
14 commits Select commitHold shift + click to select a range
7855b2b
Mutation observer
joaquinelio6dbfc33
Update 2-ui/99-ui-misc/01-mutation-observer/article.md
joaquineliof55cdab
Update 2-ui/99-ui-misc/01-mutation-observer/article.md
joaquinelioeffe663
Update 2-ui/99-ui-misc/01-mutation-observer/article.md
joaquineliob633d05
Update 2-ui/99-ui-misc/01-mutation-observer/article.md
joaquinelioe28113d
Update 2-ui/99-ui-misc/01-mutation-observer/article.md
joaquinelio468f325
Update 2-ui/99-ui-misc/01-mutation-observer/article.md
joaquinelio82859a9
Update 2-ui/99-ui-misc/01-mutation-observer/article.md
joaquinelio59392b3
Update 2-ui/99-ui-misc/01-mutation-observer/article.md
joaquinelioe8738ca
Update 2-ui/99-ui-misc/01-mutation-observer/article.md
joaquinelioc57330d
Update 2-ui/99-ui-misc/01-mutation-observer/article.md
joaquinelioc1daaf4
Update 2-ui/99-ui-misc/01-mutation-observer/article.md
joaquinelio0dbe2f0
Update 2-ui/99-ui-misc/01-mutation-observer/article.md
joaquinelio2e0cc49
refinando los malos consejos de mis partners
joaquinelioFile filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
188 changes: 94 additions & 94 deletions2-ui/99-ui-misc/01-mutation-observer/article.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,82 @@ | ||
# Mutation observer | ||
`MutationObserver`es un objeto incorporado que observa un elementoDOMy dispara uncallbackcuando hay cambios en él. | ||
Primero veremos su sintaxis, luego exploraremos un caso de la vidareal para ver dónde puede ser útil. | ||
##Sintaxis | ||
`MutationObserver`es fácil de usar. | ||
Primero creamos un observador con una función callback: | ||
```js | ||
let observer = new MutationObserver(callback); | ||
``` | ||
Y luego lo vinculamos a un nodo DOM: | ||
```js | ||
observer.observe(node, config); | ||
``` | ||
`config`es un objeto con opciones booleanas "a qué clase de cambios reaccionar": | ||
joaquinelio marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
- `childList` --cambios en los hijos directos de `node`, | ||
- `subtree` --en todos los descendientes de `node`, | ||
- `attributes` --atributos de `node`, | ||
- `attributeFilter` --un arrayde nombres de atributos, para observar solamente a los seleccionados, | ||
- `characterData` --establece si debe observar cambios de texto en`node.data`o no, | ||
Algunas otras opciones: | ||
- `attributeOldValue` --si es`true`,tanto el valor viejo como el nuevo del atributo son pasados alcallback (ver abajo),de otro modo pasa solamente el nuevo (necesita la opción`attributes`), | ||
- `characterDataOldValue` --si es`true`,tanto el valor viejo como el nuevo de`node.data`son pasados alcallback (ver abajo),de otro modo pasa solamente el nuevo (necesita la opción`characterData`). | ||
Entonces, después de cualquier cambio, el `callback`es ejecutado: los cambios son pasados en el primer argumento como una lista objetos[MutationRecord](https://dom.spec.whatwg.org/#mutationrecord), y el observador en sí mismo como segundo argumento. | ||
Los objetos[MutationRecord](https://dom.spec.whatwg.org/#mutationrecord)tienen como propiedades: | ||
- `type` --tipo de mutación, uno de: | ||
- `"attributes"`:atributo modificado, | ||
- `"characterData"`:dato modificado, usado para nodos de texto, | ||
- `"childList"`:elementos hijos agregados o quitados, | ||
- `target` --dónde ocurrió el cambio: un elemento para `"attributes"`,o un nodo de texto para`"characterData"`,o un elemento para una mutación de`"childList"`, | ||
- `addedNodes/removedNodes` --nodos que fueron agregados o quitados, | ||
- `previousSibling/nextSibling` --los nodos "hermanos", previos y siguientes a los nodos agregados y quitados, | ||
- `attributeName/attributeNamespace` --el nombre onamespace (para XML)del atributo cambiado, | ||
- `oldValue` --el valor previo, solamente cambios de atributo o cambios de texto si se establece la opción correspondiente `attributeOldValue`/`characterDataOldValue`. | ||
Por ejemplo, aquí hay un`<div>`con un atributo`contentEditable`. Ese atributo nos permite poner el foco en él y editarlo. | ||
```html run | ||
<div contentEditable id="elem">Click and <b>edit</b>, please</div> | ||
<script> | ||
let observer = new MutationObserver(mutationRecords => { | ||
console.log(mutationRecords); // console.log(los cambios) | ||
}); | ||
//observa todo exceptuando atributos | ||
observer.observe(elem, { | ||
childList: true, //observa hijos directos | ||
subtree: true, //y descendientes inferiores también | ||
characterDataOldValue: true //pasa el dato viejo alcallback | ||
}); | ||
</script> | ||
``` | ||
Si ejecutamos este código en el navegador, el foco en el`<div>`dado y el cambio en texto dentro de`<b>edit</b>`, `console.log`mostrará una mutación: | ||
```js | ||
mutationRecords = [{ | ||
type: "characterData", | ||
oldValue: "edit", | ||
target: <text node>, | ||
//otras propiedades vacías | ||
}]; | ||
``` | ||
Si hacemos operaciones de edición más complejas, como eliminar el `<b>edit</b>`,el evento de mutación puede contener múltiples registros de mutación: | ||
```js | ||
mutationRecords = [{ | ||
@@ -85,75 +85,75 @@ mutationRecords = [{ | ||
removedNodes: [<b>], | ||
nextSibling: <text node>, | ||
previousSibling: <text node> | ||
//otras propiedades vacías | ||
}, { | ||
type: "characterData" | ||
target: <text node> | ||
// ...detalles de mutación dependen de cómo el navegador maneja tal eliminación | ||
//puede unir dos nodos de texto adyacentes "edit "y ", please"en un nodo | ||
//o puede dejarlos como nodos de texto separados | ||
}]; | ||
``` | ||
Así, `MutationObserver`permite reaccionar a cualquier cambio dentro del subárbol DOM. | ||
##Uso para integración | ||
¿Cuándo puede ser práctico esto? | ||
Imagina la situación cuando necesitas añadir un script de terceros que contiene funcionalidad útil pero que también hace algo no deseado, por ejemplo añadir publicidad `<div class="ads">Unwanted ads</div>`. | ||
Naturalmente elscriptde terceras partesnoproporciona mecanismos para removerlo. | ||
Usando `MutationObserver` podemos detectar cuándo aparece el elemento no deseado en nuestro DOMy removerlo. | ||
Hay otras situaciones, como cuando unscriptde terceras partes agrega algo en nuestro documento y quisiéramos detectarlo para adaptar nuestra página y cambiar el tamaño de algo dinámicamente, etc. | ||
`MutationObserver`permite implementarlo. | ||
##Uso para arquitectura | ||
Hay también situaciones donde`MutationObserver`es bueno desde el punto de vista de la arquitectura. | ||
Digamos que estamos haciendo un sitio web acerca de programación. Naturalmente, los artículos y otros materiales pueden contener fragmentos de código. | ||
Tal fragmento en un markupHTMLse ve como esto: | ||
```html | ||
... | ||
<pre class="language-javascript"><code> | ||
//aquí el código | ||
let hello = "world"; | ||
</code></pre> | ||
... | ||
``` | ||
También usaremos una librería JavaScriptde "highlighting" para resaltar elementos en nuestro sitio, por ejemplo[Prism.js](https://prismjs.com/).Una llamada a `Prism.highlightElem(pre)`examina el contenido de tales elementos`pre`y les agregatagsy stylesespeciales para obtener sintaxis resaltada con color, similares a los que ves en esta página. | ||
¿Exactamente cuándo ejecutar tal método de highlighting? Podemos hacerlo en el evento `DOMContentLoaded`, o al final de la página. En el momento en que tenemos nuestroDOMlisto buscamos los elementos`pre[class*="language"]`y llamamos `Prism.highlightElem`en ellos: | ||
```js | ||
//resaltar todos los fragmentos de código en la página | ||
document.querySelectorAll('pre[class*="language"]').forEach(Prism.highlightElem); | ||
``` | ||
Todo essimplehasta ahora, ¿verdad? Hay fragmentos de código`<pre>`enHTML y los resaltamos. | ||
Continuemos. Digamos que vamos a buscar dinámicamente material desde un servidor. Estudiaremos métodos para ello [más adelante](info:fetch) en el tutorial. Por ahora solamente importa que buscamos un artículoHTMLdesde un servidor web y lo mostramos bajo demanda: | ||
```js | ||
let article = /*busca contenido nuevo desde un servidor */ | ||
articleElem.innerHTML = article; | ||
``` | ||
El nuevo elemento HTML`article`puede contener fragmentos de código. Necesitamos llamar`Prism.highlightElem`en ellos, de otro modo no se resaltarían. | ||
**¿Dónde y cuándo llamar`Prism.highlightElem`en un artículo cargado dinámicamente?** | ||
Podríamos agregar el llamado al código que carga un "article", como esto: | ||
```js | ||
let article = /*busca contenido nuevo desde un servidor */ | ||
articleElem.innerHTML = article; | ||
*!* | ||
@@ -162,38 +162,38 @@ snippets.forEach(Prism.highlightElem); | ||
*/!* | ||
``` | ||
...Pero imagina que tenemos muchos lugares en el código donde cargamos contenido: artículos, cuestionarios, entradas de foros. ¿Necesitamos poner el llamado al "highlighting" en todos lugares? No es muy conveniente, y es fácil de olvidar además. | ||
¿Y si el contenido es cargado por un módulo de terceras partes? Por ejemplo tenemos un foro, escrito por algún otro, que carga contenido dinámicamente y quisiéramos añadirle sintaxis dehighlighting. A nadie le gusta emparchar scripts de terceras partes. | ||
Afortunadamente hay otra opción. | ||
Podemos usar`MutationObserver`para detectar automáticamente cuándo los fragmentos de código son insertados en la página y resaltarlos. | ||
Entonces manejaremos la funcionalidad de "highlighting" en un único lugar, liberándonos de la necesidad de integrarlo. | ||
###Demo dehighlightdinámico | ||
Aquí el ejemplo funcionando. | ||
Si ejecutas el código, este comienza a observar el elemento debajo y resalta cualquier fragmento de código que aparezca allí: | ||
```js run | ||
let observer = new MutationObserver(mutations => { | ||
for(let mutation of mutations) { | ||
// examinenodos nuevos, ¿hay algo para resaltar? | ||
for(let node of mutation.addedNodes) { | ||
//seguimos elementos solamente, saltamos los otros nodos (es decir nodos de texto) | ||
if (!(node instanceof HTMLElement)) continue; | ||
//verificamos que el elemento insertado sea un fragmento de código | ||
if (node.matches('pre[class*="language-"]')) { | ||
Prism.highlightElement(node); | ||
} | ||
//¿o tal vez haya un fragmento de código en su sub-árbol? | ||
for(let elem of node.querySelectorAll('pre[class*="language-"]')) { | ||
Prism.highlightElement(elem); | ||
} | ||
@@ -207,18 +207,18 @@ let demoElem = document.getElementById('highlight-demo'); | ||
observer.observe(demoElem, {childList: true, subtree: true}); | ||
``` | ||
Aquí, abajo, hay un elementoHTML y JavaScriptque lo llena dinámicamente usando `innerHTML`. | ||
Por favor ejecuta el código anterior (arriba, que observa aquel elemento) y luego el código de abajo. Verás cómo`MutationObserver`detecta y resalta el fragmento. | ||
<p id="highlight-demo" style="border: 1px solid #ddd">A demo-element with <code>id="highlight-demo"</code>, run the code above to observe it.</p> | ||
El siguiente código llena su `innerHTML`,lo que causa que`MutationObserver`reaccione y resalte su contenido: | ||
```js run | ||
let demoElem = document.getElementById('highlight-demo'); | ||
//inserta contenido con fragmentos de código | ||
demoElem.innerHTML = `A code snippet is below: | ||
<pre class="language-javascript"><code> let hello = "world!"; </code></pre> | ||
<div>Another one:</div> | ||
@@ -228,39 +228,39 @@ demoElem.innerHTML = `A code snippet is below: | ||
`; | ||
``` | ||
Ahora tenemos un `MutationObserver`que puede rastrear todo el "highlighting" en los elementos observados del`document` entero. Podemos agregar o quitar fragmentos de código en elHTMLsin siquiera pensar en ello. | ||
##Métodos adicionales | ||
Hay un método para detener la observación del nodo: | ||
- `observer.disconnect()` --detiene la observación. | ||
Cuando detenemos la observación, algunos cambios todavía podrían quedar sin ser procesados por el observador. | ||
- `observer.takeRecords()` --obtiene una lista de registros de mutaciones sin procesar, aquellos que ocurrieron pero el callback no manejó. | ||
Estos métodos pueden ser usados juntos, como esto: | ||
```js | ||
//quisiéramos detener el rastreo de cambios | ||
observer.disconnect(); | ||
//manejar algunas mutaciones que no fueron procesadas | ||
let mutationRecords = observer.takeRecords(); | ||
... | ||
``` | ||
```smart header="Interacción con la recolección de basura" | ||
Los observadores usan internamente referencias débiles. Esto es: si un nodo es quitado del DOM y se hace inalcanzable, se vuelve basura a ser recolectada. | ||
El mero hecho de que un nodoDOMsea observado no evita la recolección de basura. | ||
``` | ||
##Resumen | ||
`MutationObserver`puede reaccionar a cambios en elDOM:atributos, elementos añadidos y quitados, contenido de texto. | ||
Podemos usarlo para rastrear cambios introducidos por otras partes de nuestro código o bien para integrarlo con scripts de terceras partes. | ||
`MutationObserver`puede rastrear cualquier cambio. Las opciones de `config` permiten establecer qué se va a observar, se usa para optimización y no desperdiciar recursos en llamados alcallbackinnecesarios. |
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.