Saltar al contenido principal

Uso de slots HTML para renderizar vistas de plataforma en la web

Los iframes en Flutter web solían recargarse debido a la forma en que se realizaban algunas operaciones DOM. Un cambio en la forma en que las aplicaciones web de Flutter renderizan las vistas de plataforma las hace estables (evitando recargas de iframes y otros problemas con etiquetas de video o formularios que potencialmente perdían su State).

Resumen

#

Flutter ahora renderiza todas las vistas de plataforma web en una ubicación consistente del DOM, como hijos directos de flt-glass-pane (independientemente del backend de renderizado: html o canvaskit). Las vistas de plataforma son luego "ubicadas" en la posición correcta del DOM de la App con características estándar de HTML.

Hasta este cambio, Flutter web modificaba el estilo del contenido renderizado de una vista de plataforma para posicionarlo/dimensionarlo en el espacio disponible. Este ya no es el caso. Los usuarios ahora pueden decidir cómo desean utilizar el espacio asignado a su vista de plataforma por el framework.

Contexto

#

El framework de Flutter realiza ajustes frecuentes en su árbol de renderizado para optimizar las operaciones de pintura que se realizan finalmente por fotograma (frame). En la web, estos cambios en el árbol de renderizado a menudo resultan en operaciones DOM.

Flutter web solía renderizar sus vistas de plataforma (widgets HtmlElementView) directamente en su correspondiente posición del DOM.

El uso de ciertos elementos DOM como el "objetivo" (target) de algunas operaciones DOM hace que esos elementos pierdan su estado interno. En la práctica, esto significa que las etiquetas iframe se van a recargar, los reproductores de video podrían reiniciarse o un formulario editable podría perder sus ediciones.

Flutter ahora renderiza las vistas de plataforma utilizando elementos slot dentro de un único shadow root a nivel de aplicación. Los elementos slot se pueden agregar/eliminar/mover por el Shadow DOM sin afectar el contenido insertado subyacente (que se renderiza en una ubicación constante)

Este cambio se realizó para:

  • Estabilizar el comportamiento de las vistas de plataforma en Flutter web.
  • Unificar cómo se renderizan las vistas de plataforma en la web para ambos backends de renderizado (html y canvaskit).
  • Proporcionar una ubicación predecible en el DOM que permita a los desarrolladores utilizar CSS de forma confiable para aplicar estilos a sus vistas de plataforma, y utilizar otras API estándar de DOM, como querySelector y getElementById.

Descripción del cambio

#

Una aplicación web de Flutter ahora se renderiza dentro de un shadow root común en el que los elementos slot representan las vistas de plataforma. El contenido real de cada vista de plataforma se renderiza como un hermano de dicho shadow root.

Antes

#
html
...

<flt-glass-pane>
  ...
  <div id="platform-view">Contents</div> <!-- canvaskit -->
  <!-- OR -->
  <flt-platform-view>
    #shadow-root
    | <div id="platform-view">Contents</div> <!-- html -->
  </flt-platform-view>
  ...
</flt-glass-pane>

...

Después

#
html
...

<flt-glass-pane>
  #shadow-root
  | ...
  | <flt-platform-view-slot>
  |   <slot name="platform-view-1" />
  | </flt-platform-view-slot>
  | ...
  <flt-platform-view slot="platform-view-1">
    <div id="platform-view">Contents</div>
  </flt-platform-view>
  ...
</flt-glass-pane>

...

Después de este cambio, cuando el framework necesita mover nodos DOM, opera sobre flt-platform-view-slots, que solo contienen un elemento slot. El slot proyecta los contenidos definidos en elementos flt-platform-view fuera del shadow root. Los elementos flt-platform-view nunca son el objetivo de las operaciones DOM del framework, lo que evita los problemas de recarga.

Desde la perspectiva de una aplicación, este cambio es transparente. Sin embargo, este se considera un breaking change porque algunas pruebas asumen cosas sobre el DOM interno de una aplicación web de Flutter y fallan.

Guía de migración

#

Programar

#

El motor puede imprimir un mensaje de advertencia en la consola similar a:

bash
Height of Platform View type: [$viewType] may not be set. Defaulting to `height: 100%`.
Set `style.height` to any appropriate value to stop this message.

o:

bash
Width of Platform View type: [$viewType] may not be set. Defaulting to `width: 100%`.
Set `style.width` to any appropriate value to stop this message.

Anteriormente, el contenido devuelto por las funciones PlatformViewFactory era redimensionado y posicionado por el framework. En su lugar, Flutter ahora dimensiona y posiciona <flt-platform-view-slot>, que es el padre del slot donde se proyecta el contenido.

Para detener la advertencia anterior, las vistas de plataforma deben establecer las propiedades style.width y style.height de su elemento raíz en cualquier valor apropiado (que no sea nulo).

Por ejemplo, para hacer que el html.Element raíz llene todo el espacio disponible asignado por el framework, establece sus propiedades style.width y style.height en '100%':

dart
ui.platformViewRegistry.registerViewFactory(viewType, (int viewId) {
  final html.Element htmlElement = html.DivElement()
    // ..other props
    ..style.width = '100%'
    ..style.height = '100%';
  // ...
  return htmlElement;
});

Si se utilizan otras técnicas para diseñar la vista de plataforma (como inset: 0), un valor de auto para width y height es suficiente para detener la advertencia.

Lee más sobre el CSS width y el CSS height.

Pruebas

#

Después de este cambio, el código de prueba del usuario no necesita inspeccionar profundamente los contenidos del shadow root de la aplicación. Todos los contenidos de la vista de plataforma se colocarán como hijos directos de flt-glass-pane, envueltos en un elemento flt-platform-view.

Evita mirar dentro del shadow root de flt-glass-pane, se considera un "detalle de implementación privado" y su marcado puede cambiar en cualquier momento, sin previo aviso.

(Consulta los PR relevantes a continuación para ver ejemplos de las "migraciones" descritas anteriormente).

Timeline

#

Llegó en la versión: 2.3.0-16.0.pre
En lanzamiento estable: 2.5

Referencias

#

Documento de diseño:

Issues relevantes:

PRs relevantes: