Saltar al contenido principal

dart:html

Aprende sobre las características principales de la biblioteca dart:html de Dart.

Usa la biblioteca dart:html para programar el navegador, manipular objetos y elementos en el DOM, y acceder a las APIs de HTML5. DOM significa Document Object Model (Modelo de Objetos del Documento), que describe la jerarquía de una página HTML.

Otros usos comunes de dart:html son la manipulación de estilos (CSS), la obtención de datos mediante solicitudes HTTP y el intercambio de datos usando WebSockets. HTML5 (y dart:html) tienen muchas APIs adicionales que esta sección no cubre. Solo las aplicaciones web pueden usar dart:html, no las aplicaciones de línea de comandos.

Para usar la biblioteca HTML en tu aplicación web, importa dart:html:

dart
import 'dart:html';

Manipulación del DOM

#

Para usar el DOM, necesitas saber sobre ventanas, documentos, elementos y nodos.

Un objeto Window representa la ventana real del navegador web. Cada Window tiene un objeto Document, que apunta al documento actualmente cargado. El objeto Window también tiene accesores a varias APIs como IndexedDB (para almacenar datos), requestAnimationFrame (para animaciones) y más. En los navegadores con pestañas, cada pestaña tiene su propio objeto Window.

Con el objeto Document, puedes crear y manipular objetos Element dentro del documento. Ten en cuenta que el documento en sí mismo es un elemento y puede ser manipulado.

El DOM modela un árbol de Nodos. Estos nodos suelen ser elementos, pero también pueden ser atributos, texto, comentarios y otros tipos de DOM. Excepto por el nodo raíz, que no tiene padre, cada nodo en el DOM tiene un padre y puede tener muchos hijos.

Búsqueda de elementos

#

Para manipular un elemento, primero necesitas un objeto que lo represente. Puedes obtener este objeto usando una consulta.

Encuentra uno o más elementos usando las funciones de nivel superior querySelector() y querySelectorAll(). Puedes realizar consultas por ID, clase, etiqueta, nombre o cualquier combinación de estos. La guía de especificación de selectores CSS define los formatos de los selectores, como el uso del prefijo # para especificar IDs y un punto (.) para las clases.

La función querySelector() devuelve el primer elemento que coincide con el selector, mientras que querySelectorAll() devuelve una colección de elementos que coinciden con el selector.

dart
// Find an element by id (an-id).
Element idElement = querySelector('#an-id')!;

// Find an element by class (a-class).
Element classElement = querySelector('.a-class')!;

// Find all elements by tag (<div>).
List<Element> divElements = querySelectorAll('div');

// Find all text inputs.
List<Element> textInputElements = querySelectorAll('input[type="text"]');

// Find all elements with the CSS class 'class'
// inside of a <p> that is inside an element with
// the ID 'id'.
List<Element> specialParagraphElements = querySelectorAll('#id p.class');

Manipulación de elementos

#

Puedes usar propiedades para cambiar el estado de un elemento. Node y su subtipo Element definen las propiedades que tienen todos los elementos. Por ejemplo, todos los elementos tienen propiedades classes, hidden, id, style y title que puedes usar para establecer el estado. Las subclases de Element definen propiedades adicionales, como la propiedad href de AnchorElement.

Considera este ejemplo de especificación de un elemento de anclaje en HTML:

html
<a id="example" href="/another/example">link text</a>

Esta etiqueta <a> especifica un elemento con un atributo href y un nodo de texto (accesible mediante una propiedad text) que contiene la cadena "link text". Para cambiar la URL a la que va el enlace, puedes usar la propiedad href de AnchorElement:

dart
var anchor = querySelector('#example') as AnchorElement;
anchor.href = 'https://dart.dev';

A menudo necesitas establecer propiedades en múltiples elementos. Por ejemplo, el siguiente código establece la propiedad hidden de todos los elementos que tienen una clase de "mac", "win" o "linux". Establecer la propiedad hidden en true tiene el mismo efecto que añadir display: none al CSS.

html
<!-- In HTML: -->
<p>
  <span class="linux">Words for Linux</span>
  <span class="macos">Words for Mac</span>
  <span class="windows">Words for Windows</span>
</p>
dart
// In Dart:
const osList = ['macos', 'windows', 'linux'];
final userOs = determineUserOs();

// For each possible OS...
for (final os in osList) {
  // Matches user OS?
  bool shouldShow = (os == userOs);

  // Find all elements with class=os. For example, if
  // os == 'windows', call querySelectorAll('.windows')
  // to find all elements with the class "windows".
  // Note that '.$os' uses string interpolation.
  for (final elem in querySelectorAll('.$os')) {
    elem.hidden = !shouldShow; // Show or hide.
  }
}

Cuando la propiedad correcta no está disponible o no es conveniente, puedes usar la propiedad attributes de Element. Esta propiedad es un Map<String, String>, donde las claves son nombres de atributos. Para ver una lista de nombres de atributos y sus significados, consulta la página de atributos de MDN. Aquí tienes un ejemplo de cómo establecer el valor de un atributo:

dart
elem.attributes['someAttribute'] = 'someValue';

Creación de elementos

#

Puedes añadir elementos a páginas HTML existentes creando nuevos elementos y adjuntándolos al DOM. Aquí tienes un ejemplo de creación de un elemento de párrafo (<p>):

dart
var elem = ParagraphElement();
elem.text = 'Creating is easy!';

También puedes crear un elemento analizando texto HTML. Cualquier elemento hijo también se analiza y se crea.

dart
var elem2 = Element.html('<p>Creating <em>is</em> easy!</p>');

Ten en cuenta que elem2 es un ParagraphElement en el ejemplo anterior.

Adjunta el elemento recién creado al documento asignando un padre al elemento. Puedes añadir un elemento a los hijos de cualquier elemento existente. En el siguiente ejemplo, body es un elemento, y sus elementos hijos son accesibles (como una List<Element>) desde la propiedad children.

dart
document.body!.children.add(elem2);

Añadir, reemplazar y eliminar nodos

#

Recuerda que los elementos son solo un tipo de nodo. Puedes encontrar todos los hijos de un nodo usando la propiedad nodes de Node, que devuelve una List<Node> (a diferencia de children, que omite los nodos que no son Element). Una vez que tengas esta lista, puedes usar los métodos y operadores habituales de List para manipular los hijos del nodo.

Para añadir un nodo como el último hijo de su padre, usa el método add() de List:

dart
querySelector('#inputs')!.nodes.add(elem);

Para reemplazar un nodo, usa el método replaceWith() de Node:

dart
querySelector('#status')!.replaceWith(elem);

Para eliminar un nodo, usa el método remove() de Node:

dart
// Find a node by ID, and remove it from the DOM if it is found.
querySelector('#expendable')?.remove();

Manipulación de estilos CSS

#

CSS, u hojas de estilo en cascada, define los estilos de presentación de los elementos del DOM. Puedes cambiar la apariencia de un elemento adjuntándole atributos de ID y clase.

Cada elemento tiene un campo classes, que es una lista. Añade y elimina clases CSS simplemente añadiendo y eliminando cadenas de esta colección. Por ejemplo, el siguiente código añade la clase warning a un elemento:

dart
var elem = querySelector('#message')!;
elem.classes.add('warning');

A menudo es muy eficiente buscar un elemento por ID. Puedes establecer dinámicamente el ID de un elemento con la propiedad id:

dart
var message = DivElement();
message.id = 'message2';
message.text = 'Please subscribe to the Dart mailing list.';

Puedes reducir el texto redundante en este ejemplo usando cascadas de métodos:

dart
var message = DivElement()
  ..id = 'message2'
  ..text = 'Please subscribe to the Dart mailing list.';

Aunque la mejor práctica es usar IDs y clases para asociar un elemento con un conjunto de estilos, a veces querrás adjuntar un estilo específico directamente al elemento:

dart
message.style
  ..fontWeight = 'bold'
  ..fontSize = '3em';

Manejo de eventos

#

Para responder a eventos externos como clics, cambios de enfoque y selecciones, añade un detector de eventos. Puedes añadir un detector de eventos a cualquier elemento de la página. El envío y la propagación de eventos es un tema complicado; investiga los detalles si eres nuevo en la programación web.

Añade un manejador de eventos usando element.onEvent.listen(function), donde Event es el nombre del evento y function es el manejador de eventos.

Por ejemplo, así es como puedes manejar clics en un botón:

dart
// Find a button by ID and add an event handler.
querySelector('#submitInfo')!.onClick.listen((e) {
  // When the button is clicked, it runs this code.
  submitData();
});

Los eventos pueden propagarse hacia arriba y hacia abajo a través del árbol DOM. Para descubrir qué elemento originó el evento, usa e.target:

dart
document.body!.onClick.listen((e) {
  final clickedElem = e.target;
  // ...
});

Para ver todos los eventos para los que puedes registrar un detector de eventos, busca las propiedades "onEventType" en la documentación de la API para Element y sus subclases. Algunos eventos comunes incluyen:

  • change
  • blur
  • keyDown
  • keyUp
  • mouseDown
  • mouseUp

Uso de recursos HTTP con HttpRequest

#

Deberías evitar usar directamente dart:html para realizar solicitudes HTTP. La clase HttpRequest en dart:html depende de la plataforma y está vinculada a una única implementación. En su lugar, usa una biblioteca de nivel superior como package:http.

El tutorial Fetch data from the internet explica cómo realizar solicitudes HTTP usando package:http.

Envío y recepción de datos en tiempo real con WebSockets

#

Un WebSocket permite que tu aplicación web intercambie datos con un servidor de forma interactiva, sin necesidad de realizar sondeos (polling). Un servidor crea el WebSocket y escucha solicitudes en una URL que comienza con ws://; por ejemplo, ws://127.0.0.1:1337/ws. Los datos transmitidos a través de un WebSocket pueden ser una cadena o un blob. A menudo, los datos son una cadena en formato JSON.

Para usar un WebSocket en tu aplicación web, primero crea un objeto WebSocket, pasando la URL del WebSocket como argumento:

dart
var ws = WebSocket('ws://echo.websocket.org');

Envío de datos

#

Para enviar datos de tipo cadena a través de WebSocket, usa el método send():

dart
ws.send('Hello from Dart!');

Recepción de datos

#

Para recibir datos a través de WebSocket, registra un detector de eventos de mensaje:

dart
ws.onMessage.listen((MessageEvent e) {
  print('Received message: ${e.data}');
});

El manejador de eventos de mensaje recibe un objeto MessageEvent objeto. El campo data de este objeto contiene los datos del servidor.

Manejo de eventos de WebSocket

#

Tu aplicación puede manejar los siguientes eventos de WebSocket: open, close, error, y (como se mostró anteriormente) message. Aquí tienes un ejemplo de un método que crea un objeto WebSocket y registra manejadores para los eventos open, close, error y message:

dart
void initWebSocket([int retrySeconds = 1]) {
  var reconnectScheduled = false;

  print('Connecting to websocket');

  void scheduleReconnect() {
    if (!reconnectScheduled) {
      Timer(
        Duration(seconds: retrySeconds),
        () => initWebSocket(retrySeconds * 2),
      );
    }
    reconnectScheduled = true;
  }

  ws.onOpen.listen((e) {
    print('Connected');
    ws.send('Hello from Dart!');
  });

  ws.onClose.listen((e) {
    print('Websocket closed, retrying in $retrySeconds seconds');
    scheduleReconnect();
  });

  ws.onError.listen((e) {
    print('Error connecting to ws');
    scheduleReconnect();
  });

  ws.onMessage.listen((MessageEvent e) {
    print('Received message: ${e.data}');
  });
}

Más información

#

Esta sección apenas araña la superficie del uso de la biblioteca dart:html. Para más información, consulta la documentación de dart:html. Dart tiene bibliotecas adicionales para APIs web más especializadas, como web audio, IndexedDB y WebGL.

Para más información sobre las bibliotecas web de Dart, consulta la visión general de las bibliotecas web.