Saltar al contenido principal

Comenzando con la interoperabilidad con JavaScript

Un ejemplo básico del uso de APIs de navegador y una librería JS empaquetada.

Este tutorial te enseña los conceptos básicos de la interacción con JavaScript en código Dart utilizando varias APIs del navegador y de JavaScript.

Accede y define un objeto de JavaScript

#

Para acceder a un objeto global de JavaScript, como el objeto document del navegador, declara un getter de nivel superior anotado con @JS y externo (external). Esto devuelve el valor como un JSObject opaco.

dart
import 'dart:js_interop';

// All top-level JS interop APIs need the @JS annotation.
@JS()
external JSObject get document;

Un JSObject es opaco y no proporciona seguridad de tipos ni autocompletado de código. Para agregar miembros con seguridad de tipos, define un tipo de interoperabilidad utilizando un extension type. Esto actúa como una interfaz, permitiéndote declarar más APIs de interoperabilidad como miembros externos (external). Puedes definir un tipo de interoperabilidad utilizando extension types para visualizarlo de manera diferente:

dart
@JS()
external Document get document;

extension type Document._(JSObject _) implements JSObject {}

Ahora, puedes agregar métodos externos a tu interfaz Document. Por ejemplo, agrega el método de instancia createElement():

dart
extension type Document._(JSObject _) implements JSObject {
  external JSObject createElement(JSString tag);
}

Con el método createElement definido, puedes llamarlo en el objeto document. Ten en cuenta que debes convertir 'button' de un String a un JSString usando el método de extensión .toJS.

dart
var button = document.createElement('button'.toJS);

Los valores que se pasan hacia y desde las APIs de interoperabilidad deben ser un tipo de interoperabilidad (como JSObject o JSString) o un tipo primitivo permitido de Dart.

Usa conversiones automáticas de tipos

#

El compilador convierte automáticamente la mayoría de los tipos primitivos de Dart (como String, num, bool y null), por lo que a menudo puedes usarlos directamente en las firmas de interoperabilidad para simplificar tu código.

Por ejemplo, puedes reescribir la declaración createElement de la sección anterior para aceptar directamente un String de Dart. Por ejemplo:

dart
external JSObject createElement(String tag);

Ahora, puedes llamarlo sin la conversión explícita .toJS. Por ejemplo:

dart
var button = document.createElement('button');

Para agregar el botón recién creado al cuerpo (body) del documento, primero define tipos de interoperabilidad para el body y su método appendChild():

dart
extension type Document._(JSObject _) implements JSObject {
  external JSObject createElement(String tag);
  external Body get body;
}

extension type Body._(JSObject _) implements JSObject {
  external JSObject appendChild(JSObject child);
}

Con estas definiciones, puedes crear un botón y agregarlo a la página:

dart
var button = document.createElement('button');
document.body.appendChild(button);

Maneja eventos y callbacks

#

Para manejar las interacciones del usuario, como el clic de un botón, puedes registrar un escucha de eventos utilizando addEventListener().

Primero, crea una interfaz para un elemento de botón. Luego, llama a addEventListener con el nombre del evento y una función de callback.

dart
extension type ButtonElement(JSObject _) implements JSObject {
  external void addEventListener(String event, JSFunction listener);
}
dart
var button = ButtonElement(document.createElement('button'));
document.body.appendChild(button);
button.addEventListener('click', (JSObject event) {
  print('Clicked!');
}.toJS);

Los callbacks convertidos a JS con .toJS tienen las mismas limitaciones de tipo que otras APIs de interoperabilidad, en el sentido de que sus parámetros y valores de retorno deben ser tipos de interoperabilidad o primitivos compatibles.

Trabaja con Promesas (Promises) y Arrays

#

La interoperabilidad con JavaScript proporciona ayudantes (helpers) para otros tipos comunes, como la conversión de Promises de JavaScript hacia y desde Futures de Dart, y Arrays hacia y desde Lists.

Promesas (Promises) y Futures

#

Este ejemplo utiliza la API fetch, que devuelve una Promise. La extensión .toDart convierte la Promise en un Future, de modo que puedes usar await para esperar su resultado en Dart:

dart
import 'dart:js_interop';

extension type Response._(JSObject _) implements JSObject {
  external bool get ok;
}

@JS()
external Response fetch(String resource);

void main() async {
  var response = await fetch('image.png').toDart;
  print(response.ok);
}

Arrays y Listas (Lists)

#

Este ejemplo llama al método estático Array.of de JavaScript para crear un JSArray. Luego convierte el array a una List de Dart, itera sobre ella e imprime cada elemento.

dart
import 'dart:js_interop';

@JS('Array.of')
external JSArray<JSString> arrayOf(String a, String b);

void main() {
  var array = arrayOf('hello', 'world');
  var list = array.toDart;
  for (var element in list) {
    print(element.toDart);
  }
}

Al convertir un tipo genérico como una List, sus elementos ya deben ser tipos de JS interop. Por ejemplo, para convertir una List<String>, primero debes convertir cada String en un JSString.

dart
// Option 1: Create the list with JS types initially.
List<JSString> list = ['hello'.toJS, 'world'.toJS];
JSArray jsArray1 = list.toJS;

// Option 2: Map a Dart list to a list of JS types.
List<String> dartList = ['hello', 'world'];
JSArray jsArray2 = dartList.map((e) => e.toJS).toList().toJS;

Más información

#
  • Para obtener más información sobre las conversiones de tipo, consulta Conversiones.
  • Para obtener más información sobre cómo escribir APIs de interoperabilidad, consulta la Guía de uso.
  • To access common utility functions, see:
  • El paquete package:web expone muchas de las APIs del navegador (incluyendo las utilizadas en los ejemplos anteriores) a través de declaraciones de interoperabilidad.