Api Resizebserver: Un Tutorial Con Ejemplos

Recientemente, me presentaron a un diseño desafiante en funcionamiento: un componente con una fila de botones en la parte superior. El problema fue que cada vez que el componente no era lo suficientemente ancho para caber en todos los botones, estas acciones necesitaban ser movidas a un menú desplegable.

Construir una UI que puede adaptarse a los anchos variados de la pantalla y los anchos de contenedores variados son un desafío que se ha vuelto más común con la creciente popularidad de las estructuras basadas en componentes, como Raact y VUE.JS como componentes web nativos. Es posible que el mismo componente deba funcionar en un área de contenido principal grande y en una columna lateral estrecha, en todos los dispositivos, nada menos.

¿Qué es ResizeBSERVER?

ResizEbserver API es una gran herramienta para crear UIS que puede adaptarse a la pantalla del usuario y al ancho del contenedor. Usando un ResizeBServer, podemos llamar a una función siempre que se cambie de tamaño un elemento, al igual que escuche una ventana de eventos de cambio de tamaño.

Los casos de uso para ResizEBSERVER pueden no ser inmediatamente obvios, así que echemos un vistazo a algunos ejemplos prácticos.

Llene un contenedor

Para nuestro primer ejemplo, imagine que desea mostrar una fila de fotos inspiradoras aleatorias debajo de la sección del héroe de su página. Solo desea cargar la cantidad de fotos que deben completar esta línea y desea agregar o eliminar fotos según sea necesario cuando cambie el ancho del contenedor.

Podríamos aprovechar los eventos de cambio de tamaño, pero tal vez el ancho de nuestro componente también cambie siempre que un usuario recaque un panel lateral. Ahí es donde el resizebserver se vuelve útil.

Vea el contenedor de llenado de stylus resizeobserver por Kevin Drum (@KevinleEdrum) en CodeEpen.

Mirando a nuestro JavaScript para este ejemplo, las primeras líneas configuran nuestro observador:

const resizebserver = New ResizeBServer (ONRESIZE); Resizeobserver.observe (document.queryselector («contenedor»));

Creamos un nuevo resizabserver, pasando una función de devolución de llamada al constructor. Luego informamos a nuestro nuevo observador qué elemento observa.

Recuerde que es posible observar múltiples elementos con un solo observador si encuentra la necesidad.

Después de eso, llegamos a la lógica central de nuestra IU:

const image_max_width = 200; const image_min_width = 100; Función de la función (entradas) {entrada const = entradas [0]; Const conteider = Entry.Target; / * Calcule cuántas imágenes se ajustan al contenedor. * / Const ImagesNeed = math.ceil (entrada.contentrect.width / image_max_width); Deje imágenes = contenedor.children; / * Retire las imágenes según sea necesario. * / While (images.length imagesneed) {Images [images.length-1].remove (); } / * Agregar imágenes según sea necesario. * / while (images.length

Después de configurar los anchos mínimos y máximos para nuestras imágenes (para que puedan llenar todo el ancho), declaramos nuestra Rebol de llamada ONRESIZE. El ResizeObserver pasa una matriz de objetos de resizabserverRentry para nuestra función.

A medida que estamos observando solo un elemento, nuestra matriz contiene solo una entrada. Este objeto de entrada proporciona las nuevas dimensiones del elemento. (a través de la propiedad con contracción), así como una referencia al propio elemento (la propiedad de destino).

Con el nuevo ancho de nuestro elemento actualizado, podemos calcular la cantidad de imágenes y comparar con el número de imágenes ya mostradas (los niños del elemento de contenedor). Después de eso, es tan simple como eliminar Elementos o agregar nuevos elementos.

Para fines de demostración, estoy mostrando imágenes aleatorias de Lorem Picsum.

Cambio de una línea flexible a una columna

Nuestro segundo ejemplo aborda un problema que es bastante común: convertir una línea flexible de elementos en una columna siempre que estos elementos no se ajusten a un solo. línea (sin rebosar ni romperse).

Con la API de resizabserver, esto es totalmente posible.

Vea la dirección STYLUS RESIVEBSERVER-FLEX DE KEVIN DUMT (@KEVINLEEDRUM) en CodeEpen.

Nuestra función ONRESIZE en este ejemplo se ve así:

Deje que Rowidth; Función de la función (entradas) {entrada const = entradas [0]; contenedor Const = Entry.Target; Si (! Rowwidth) Rowwidth = Array.Desfrom (contenedor.Children).Reduce ((ACC, EL) = GETELWIDTH (EL) + ACC, 0); const ISOVERFLOWING = Rowidth Entry.Contentrect.Width; ¡Si (ISOVERFLOWING! CONTENEDOR.CLASSLIST.Contains («contenedorEntrama ((() = {contenedor.classlist.add (» contenedor-vertical «);}); } De lo contrario, si (! Isoverflowing conteder.classlist.contains («contenedor de contenedores (() = {contenedor.classlist.remove (contenedor-vertical»);}); }}

La función agrega los anchos de todos los botones, incluido el margen, para descubrir el ancho del contenedor para mostrar todos los botones en una línea. Estamos almacenando en caché este ancho calculado en un ancho de fila variable cuyo alcance está fuera de nuestra función, de modo que no nos pierda el tiempo que lo calcule cada vez que se cambia el elemento.

Tan pronto como sepamos el ancho mínimo requerido para todos los botones, podemos compararlo con el nuevo ancho del contenedor y gire la línea en una columna si los botones no encajan. Para lograr esto, simplemente estamos alternando una clase de contenedor vertical en el contenedor.

y consultas de contenedores?

Algunos de los problemas que pueden resolverse con ResizEbserver se pueden resolver mucho más eficientes con las consultas del contenedor CSS, que ahora se admiten en Chrome Canary. Sin embargo, una desventaja de las consultas del contenedor es que requieren valores conocidos para un ancho mínimo, relación de aspecto, etc.

ResizEbserver, por otro lado, nos brinda energía ilimitada para examinar todo el regalo y escribir la lógica como compleja como queremos. Además, ya es compatible con todos los navegadores principales.

Componente de la barra de herramientas Responsivos

¿Recuerda ese problema de trabajo que mencioné en el que necesitaba mover los botones que responden a un menú desplegable? Nuestro ejemplo final es muy similar.

Conceptualmente, este ejemplo se basa en el ejemplo anterior porque, una vez más, estamos revisando cuando estamos revisando un contenedor. En ese caso, debemos repetir esta verificación cada vez que eliminemos un botón para ver si necesitamos eliminar otro botón.

Para reducir la cantidad de cliché, estoy usando VUE.JS para este ejemplo, aunque la idea debería funcionar para cualquier estructura. También estoy usando Popper para colocar el menú desplegable.

Vea la barra de herramientas del tambor Kevin (@KevinleEdrum) de STYLUS RESIVEBSERVERSESIONSIONSIONSIONSIONSIONSIONSIONSIONSION EN COODEPEN.

Hay un poco más de código para este ejemplo, pero la descomponemos. Todas nuestras lógicas se encuentran dentro de una instancia de VUE (o Componente):

NUEVO VUE ({EL: «# APLICACIÓN», FECHA () {DEVOLUCIÓN {acciones: [«Editar», «Guardar», «Copia «,» Cambiar nombre «,» Compartir «,» Eliminar «], Ismenuopen: Falso, menú: // acciones que deben mostrarse en el menú};},

Tenemos tres propiedades de importancia Datos que conforman el «estado» de nuestro componente.

La matriz de acciones enumera todas las acciones que debemos mostrar en nuestra UI, el Ismenuopen Boolean es una bandera que podemos cambiar para mostrar u ocultar el menú de acción. Menuacciones Matrix contendrá una lista de acciones que deben mostrarse en el menú (cuando haya suficiente espacio para mostrarlos como botones)

Actualizaremos esta matriz según sea necesario en nuestra devolución de llamada ONSIZE y nuestro HTML Will Se actualizará automáticamente.

calculado: {ActionButtons () {/ / acciones que deben mostrarse como botones fuera del menú Retorno esta.actions.Filter ((acción) =! Esto.menuactions.includes (acción ));}},

Estamos cantando una propiedad compuesta VUE llamada ActionButtons para generar una serie de acciones que deben mostrarse como botones. Es el inverso de menú.

Con estas dos matrices, nuestro modelo HTML puede simplemente iterar ambos para crear los botones y los elementos del menú, respectivamente:

Si no está familiarizado con el modelo Vue Syntax, no te preocupes demasiado. Sepa que estamos creando botones y elementos de menú dinámicamente con los manipuladores de eventos de estos dos matrices, y estamos mostrando u ocultando un menú desplegable basado en el Ismenuopen Boolean.

Los atributos de referencia también nos permiten acceder a estos elementos de nuestro script sin tener que usar un consulta.

VUE proporciona algunos métodos de ciclo de vida que nos permiten configurar nuestro observador cuando el componente se carga primero y lo limpia cada vez que se destruye nuestro componente:

montado () {// adjuntar resizabserver al contenedor resizebserver = nuevo resizebserver (esto.onResize); Resizeobserver.observe (esto. $ Refs.container); // Cierre el menú en cualquier documento de click.addeventlistener («clic», este.Crossemenú); }, BeForedstroy () {// Limpie el observador y el evento, el escucha resizeBserver.disconnect (); Document.removeEventlistener («clic», este.Crossemenu); },

Ahora viene la parte divertida, que es nuestro método de ONRESIZE:

MÉTODOS: {oneressize () {SoliciteAmationFrame (Async = {// Coloque todos los botones fuera del menú si (Esto. Menuacciones. Longitud) {esta.Menuacciones = [] [] Espere a esto. $ Siguiente ();} Const ISOVERFlowing = () = eso. $ refs.container.scrollwidth esto. $ refs.container.offsetwidth; Mueva los botones al menú hasta que el contenedor ya no esté desbordado mientras (ISOVERFLOWING () ESTE.ACIONBUTONTS.LENGIENDA) {CONST LastAtionButton = this.ActionButTontons [this.actionbuttons.length-1]; esta.menuactions.unshift); espere a este $. NextTick ();}}); },

Lo primero que puede notificar es que involucramos todo en una llamada para solicitar solicitud. Esto simplemente limita la frecuencia con la que se puede ejecutar nuestro código (generalmente 60 veces por segundo). Esto ayuda a prevenir el límite de bucle de ResizeBSERVER excede las advertencias de la consola, que pueden ocurrir cada vez que la devolución de llamada observador intenta ejecutar varias veces durante un solo marco de animación.

Con esto fuera del camino, nuestros métodos anteriores comienzan a restablecerse a un estado estándar si es necesario. El estado predeterminado es cuando todas las acciones están representadas por los botones, no hay elementos de menú.

Como parte de esta redefinición, espera una llamada a esto. $ Siguiente, quien le dice al VUE que siga adelante y actualice su regalo virtual, de modo que nuestro elemento de contenedor vuelva al ancho máximo con todos los botones que muestren.

// Coloque todos los botones del menú IF (esta.menuactions.length) {esto.menuacciones = []; Espera esto. $ Nextticick (); }

Ahora que tenemos una línea completa de botones, debemos verificar si la línea está desbordada para saber si necesitamos mover algunos de los botones a nuestro menú de acción.

Una forma sencilla de identificar si un elemento está estallando, debe comparar su dispositivo de desplazamiento con su ancho de aficionado. Si el tejido de desplazamiento es mayor, el elemento está estallando.

const isoverflowing = () = esto. $ Refs.container.scrollwidth esto. $ Refs.container.offsetwidth;

El resto de nuestro método ONRESIZE es un bucle while. Durante cada iteración, verificamos si el contenedor está estallado y, si es, movemos una acción más a los menús de la matriz. El bucle solo se interrumpe cuando ya no estamos sobrecargando el contenedor o cuando movemos todas las acciones al menú.

Tenga en cuenta que estamos esperando esto. $ Siguiente () después de cada bucle, por lo que el ancho del contenedor se puede actualizar después del cambio a esta.menuacciones.

// Mueva los botones al menú hasta que el contenedor ya no esté desbordado mientras (ISOVERFLOWING () ESTE.ACIONBUTONS.LENGIONES) {CONST LastAtionButton = this.ActionButtons [this.actionbuttons.length-1]; esta.Menuactions.UnsHift (LastAtionButton); Espera esto. $ Nextticick (); }

Esto abarca toda la magia que necesitábamos para superar este desafío. Gran parte del resto del código en nuestro componente VUE está relacionado con el comportamiento del menú desplegable, que está fuera del alcance de este artículo.

CONCLUSIÓN

Con suerte, estos ejemplos resaltan la utilidad de la API de resizabserver, particularmente en enfoques basados ??en componentes para el desarrollo frontal. Junto con las consultas de medios CSS, las consultas de contenedor y los eventos de cambio de contenedores de arriba y cercanos ayudan a construir la base de las interfaces web modernas.

Compartir