La mejor práctica para usar DOM Nivel 0 en aplicaciones modernas de JavaScript

¿Existe un set acordado de "mejores prácticas" para el uso de las collections DOM Nivel 0 en aplicaciones modernas de JavaScript? ( document.forms , document.images , etc.)

En aplicaciones que usan jQuery, he notado una tendencia a, digamos, cambiar el contenido de un menu desplegable usando $(...).html() para cambiar los nodos subyacentes, en lugar de usar element.options[] . ¿Esto se debe a que es mejor evitar las collections DOM 0, o porque jQuery hace que sea mucho más fácil cambiar la estructura DOM subyacente?

Editar: Supongo que parte de la pregunta incluye si las características anteriores son confiables entre browseres. Recuerdo que, una vez, IE agregaba tags <tbody> automáticamente a tu table, mientras que Firefox no lo hacía. Eso hizo que caminar por el tree dom sea doloroso entre browseres. Del mismo modo, element.options[] tuvo problemas al cambiar las opciones en la colección . ¿Son estos types fiables entre browseres?

Primero, gran pregunta.

La funcionalidad DOM Nivel 0-1 es mi caja de herramientas favorita para trabajar. El soporte es tremendo. Resaltaré los pros y los contras de cada subset del DOM Nivel 0 a continuación:

DOM Nivel 0 Eventos

Dado que estos se agregan como properties de un ElementNode , solo puede tener un controller. Para algunos casos (por ejemplo, delegación de events), esto es una carga. Sin embargo, creo que el DOM es lo suficientemente diverso (especialmente a medida que su proyecto se hace más grande) para tener suficiente espacio para los manejadores de nivel DOM 0. Los oyentes DOM Nivel 2 son difíciles de implementar sin una biblioteca / marco para suavizar browseres más antiguos. Incluso como desarrollador de Flash (los oyentes se usan en todas partes), los events DOM 0 son mucho más fáciles para mí. Uno de los aspectos más destacados es el hecho de que this valor está configurado para usted (sin IE piratería y tos como el otro model). Por ejemplo, considere este marcado:

<div id="foo">Cick Me!</div>

Ahora, todo lo que se necesita hacer es seleccionar y adjuntar un manejador DOM Nivel 0.

 var foo = document.getElementById("foo"); function bar() { console.log(this); //<div id="foo"> } foo.onclick = bar; 

Esa es una manera muy fácil de seleccionar elementos y una alternativa a Event.currentTarget ;

Hay una gran discusión sobre los events DOM Nivel 0 vs. los events DOM Nivel 2 aquí: [ link ]


Nivel DOM 0 HTMLCollections

Bar none, HTMLCollections son mi característica favorita del DOM. Debido a que los nodos son seleccionados por usted, no hay necesidad de ejecutar consultas. En mi opinión, hoy en día son la function DOM más olvidada. Cruce de nombres como: collection["name"] es muy útil y sin duda ayuda al atravesar formularios. Por ejemplo, considere este poco de marcado:

 <form action="./" id="foo" name="foo" method="post" onsubmit="return false;"> <fieldset> <legend>Dummy Form</legend> <input type="text" name="bar"> <select name="baz"> <option selected value="1">1</option> </select> </fieldset> </form> 

Hay muchas forms DOM Nivel 0 para abordar esto.

  1. var foo = document.forms.foo; //<form id="foo" onsubmit="return false;" method="post" name="foo" action="./">

    Demostración: http://jsbin.com/udozoz/0edit#preview

  2. var foo = document.forms[0]; //<form id="foo" onsubmit="return false;" method="post" name="foo" action="./">

    Demostración: http://jsbin.com/udozoz/2/edit#preview

  3. var foo = document.getElementById("foo"); //<form id="foo" onsubmit="return false;" method="post" name="foo" action="./">

    Demostración: http://jsbin.com/udozoz/3/edit#preview

Ciertamente, el método 3 es más preferible. Es DOM Nivel 1, y no DOM Nivel 0. Sin embargo, el cruce de nombre se ajusta naturalmente a HTMLFormElement.elements HTMLCollection . Como se supone que debes usar attributes de name en los elementos de formulario, puedes acceder fácilmente a ellos sin un atributo de id .

Ej: var baz = foo.elements.baz;

Al usar botones de opción que comparten el mismo nombre (para hacer solo uno seleccionable a la vez), puede usar HTMLFormElement.elements HTMLCollection para seleccionar todos los botones de opción . Eso es muy poderoso. Considere este marcado:

 <form action="./" id="foo" name="foo" method="post" onsubmit="return false;"> <fieldset> <legend>Radio Buttons</legend> <label for="select_1">1</label> <input id="select_1" type="radio" name="selectable" value="a"> <label for="select_2">2</label> <input id="select_2" type="radio" name="selectable" value="b"> <label for="select_3">3</label> <input id="select_3" type="radio" name="selectable" value="c"> </fieldset> </form> 

Puede usar este código simple y tener cada button de opción con el valor del atributo de name "seleccionable":

  1.  var foo = document.forms.foo; var selectables = foo.elements.selectable; console.log(selectables); //[input#select_1 a, input#select_2 b, input#select_3 c] 

    Demostración: http://jsbin.com/upiyom/edit#preview

  2.  var foo = document.forms.foo; var selectables = foo.selectable; console.log(selectables); //[input#select_1 a, input#select_2 b, input#select_3 c] 

    Demostración: http://jsbin.com/upiyom/2/edit#preview

La opción 2 le permite omitir completamente los elements HTMLCollection . Aunque ciertamente no es tan claro como la Opción 1, todavía se usa hoy en día.

Las queues de HTM se han vuelto más populosas y mucho más diversas desde la introducción del DOM Nivel 0. Por ejemplo, eche un vistazo a las queues HTMLC disponibles para una table. Es asombroso. Hay HTMLTableElement.rows , HTMLTableElement.tBodies , HTMLTableSectionElement (thead, tbody, tfoot) .rows y HTMLTableRowElement.cells . Esas collections son muy potentes y han hecho que el cruce DOM sea mucho más simple con tablas (lo que permite usarlas).


DOM Nivel 0 Propiedades

Mientras que las properties en ElementNodes no eran tan diversas en DOM Nivel 0 como lo son ahora, todavía hay un par de gems a tener en count:

HTMLInputElement.defaultChecked

defaultChecked permite omitir la búsqueda a través de un atributo checked HTMLInputElement completamente porque almacena un valor boolean basado en el valor de ese atributo. Esto significa que no tiene que pasar por soluciones descuidadas para las comstackciones de IE relacionadas con get / set / removeAttribute. Más adelante, la propiedad defaultValue también se agregará para satisfacer una necesidad similar.

document.lastModified [no estándar]

lastModified almacenará la última vez que se modificó el documento. Es una pequeña característica interesante que tiene un uso limitado.

HTMLDocument.title

title enganchará el título del documento por usted. Su uso es un pequeño nicho en el mejor de los casos.


En lo que respecta a su pregunta de tbody , los browseres actuales sí agregan un HTMLTableSectionElement (tbody) si no promueve una estructura de DOM adecuada. Debería conocer el marcado correcto de la tabla para que esto no sea un problema en el futuro :).

Ejemplo de marcado:

Incorrecto:

 <table> <!-- tbody will be inserted here and will wrap the tr --> <tr> <td>Hello, World!</tr> </tr> </table> 

Derecha:

 <table> <tbody> <tr> <td>Hello, World!</td> </tr> </tbody> </table> 

Demostración: http://jsbin.com/exomub/edit#preview


Resumen

El punto principal que necesita ser conducido a casa es que la mayor parte del DOM Nivel 0 está estandarizado en los niveles DOM 1 y 2. Esto significa que el soporte del browser es extenso (ya que es muy antiguo). No debería haber demasiada aprensión para usarlo, aparte de algunos casos extremos en comstackciones de browseres más antiguas. Al final del día, es tu elección.

Me gustaría agregar que solo he sido muy brevemente -en el pasado- empleado para desarrollar con HTML / JavaScript. Lo hago como un pasatime, así que no estoy al tanto de "historias de terror" sobre browseres / proyectos que salieron mal.

Espero que esto aclare algunas cosas.

-Mate

ElementNode – Node con nodeType == 1

HTMLCollectionNodeList de tipo Live Array recostackda por el browser

Esa es una pregunta muy interesante. Aquí están mis dos centavos.

En primer lugar, podría ser evidente, pero depende del código en el que está trabajando. Los progtwigdores profesionales pretenden seguir las mejores prácticas de la empresa (o, para empresas más grandes, en todo el equipo), y si el DOM Nivel 0 no está recomendado o prohibido por estas directrices, entonces no debe usarlo. Si se permite o no se menciona en absoluto, la decisión se resuelve en una elección personal, como para su propio código.

Ahora, no hay una desventaja técnica obvia que le impida usar el Nivel 0 si así lo desea. Por ejemplo, me sorprendería si iterar sobre element.options fuera más lento que con element.getElementsByTagName("option") o $("option", element) . La primera syntax también es posiblemente más legible que las alternativas.

El soporte del browser tampoco es un problema. El nivel 0 es más antiguo que la suciedad y ha sido respaldado por más de una década por todos los browseres de script bajo el sol.

Sin embargo, lo anterior se trata de elección , no de eficiencia , que es lo que concierne a la segunda mitad de su pregunta. De hecho, puede iterar sobre element.options o $("option", element) o $(element).children("option") con más o less la misma eficacia, pero si tiene que hacer un trabajo pesado (por ejemplo, borre los elementos existentes de la <option> y agregue los nuevos), luego usar element.innerHTML o $(element).html() será definitivamente más rápido.

Esto se debe a que la propiedad innerHTML Level 0 y el html () jQuery (que usa internamente innerHTML ) delegan todo el análisis de marcado y la manipulación DOM en el browser, que generalmente está escrito en un lenguaje de nivel inferior y está muy optimizado para estas tareas. Eliminar los elementos <option> uno por uno en un bucle de Javascript siempre será más lento en comparación, y en esta situación, usar DOM Level 0 o todas las campanas y silbidos de jQuery no hace absolutamente ninguna diferencia.

Comenzaré diciendo que no conozco ninguna statement "oficial" como "DOM Nivel 0 considerado dañino". Esta es solo mi propia opinión.

Creo que depende del caso.

El problema que tengo es que es problemático, especialmente con documentos generados / modificados dinámicamente, apuntar a elementos específicos utilizando las collections como documents.forms o documents.images . Cada vez que veo a alguien escribir document.forms[0] , me estremezco.

Los browseres actuales e incluso los no tan actuales proporcionan la capacidad a través de funciones como getElementsByTagName para simular el mismo comportamiento, pero de una manera más genérica y reutilizable. Por supuesto, cuando agrega jQuery a la mezcla, no hay ninguna razón para usar esas collections.

Las excepciones que tengo son cuando trabajas en un entorno que no es jQuery y estás accediendo a cosas como selectElement.options o tbodyElement.rows . En esos casos, es realmente más simple cuando haces cosas básicas como agregar o eliminar elementos.

En las aplicaciones que usan jQuery, he notado una tendencia a, digamos, cambiar el contenido de un menu desplegable utilizando $ (…). Html () para cambiar los nodos subyacentes, en lugar de usar element.options [] . ¿Esto se debe a que es mejor evitar las collections dom0, o porque jQuery hace que sea mucho más fácil cambiar la estructura DOM subyacente?

Eso se puede explicar con bastante facilidad. El 95% de los desarrolladores de jQuery ignoran que la DOM API existe o puede ser utilizada.

El hecho de que jQuery se abuse de cosas que el DOM puede hacer más fácilmente es simplemente causado por personas que no aprenden el DOM.

Personalmente, yo diría que usen DOM 0, pero, de nuevo, personalmente les diría que usen un shim DOM y que no usen jQuery. Todo es una cuestión de elección.

Haz lo que sea más fácil de mantener

Para bien o para mal, utilizo funciones de nivel DOM puro 0 principalmente para la debugging. A veces es más rápido inspeccionar document.forms [0] .elements for inputs.

También uso esas características cuando estoy inspeccionando alguna página que utiliza algún marco esotérico (o simplemente desconocido para mí). No tengo time para profundizar en esas abstracciones y simplemente inspeccionar collections directamente.

Creo que es mejor que conozcas todo este arsenal de DOM cero, pero es aún mejor si conoces todas estas modernas APIs puras de DOM que no saben qué nivel son más exactas. Las collections ClassList son agradables, por ejemplo. Quiero decir, si está usando un marco, siempre debe saber, ¿por qué exactamente lo necesita?