Cómo cambiar automáticamente el tamaño de un área de texto para que se ajuste a su contenido

Cómo escribir una función para cambiar automáticamente el tamaño de un área de texto cuando su contenido se expande más allá de su altura predeterminada.

Para este tutorial, vamos a utilizar el marco JavaScript de pila completa de CheatCode, Joystick. Joystick reúne un marco de interfaz de usuario de front-end con un back-end de Node.js para crear aplicaciones.

Para comenzar, querremos instalar Joystick a través de NPM. Asegúrese de estar usando Node.js 16+ antes de instalar para garantizar la compatibilidad (lea este tutorial primero si necesita aprender a instalar Node.js o ejecutar varias versiones en su computadora):

Terminal

npm i -g @joystick.js/cli

Esto instalará Joystick globalmente en su computadora. Una vez instalado, vamos a crear un nuevo proyecto:

Terminal

joystick create app

Después de unos segundos, verá un mensaje desconectado de cd en su nuevo proyecto y ejecute joystick start :

Terminal

cd app && joystick start

Después de esto, su aplicación debería estar ejecutándose y estamos listos para comenzar.

Escribiendo una función de tamaño automático

Para que nuestro código sea lo más flexible posible, para empezar, vamos a escribir un módulo reutilizable para cambiar el tamaño de los elementos del área de texto. Dentro del /lib carpeta creada para usted cuando ejecutó joystick create app , agregue un nuevo archivo autoResize.js :

/lib/autoResize.js

export default (DOMNode = {}, defaultHeight = 100) => {
  // We'll handle the resize here...
};

Para empezar, desde este archivo queremos exportar una función que tome dos argumentos:

  1. DOMNode que es el nodo DOM de JavaScript que representa el <textarea><textarea> elemento cuya altura queremos controlar.
  2. defaultHeight que es la altura mínima que se debe establecer para el área de texto si la altura de su contenido no obliga a aumentar la altura.

/lib/autoResize.js

export default (DOMNode = {}, defaultHeight = 100) => {
  if (DOMNode) {
    // We'll handle the resize logic here...
  }
};

A continuación, queremos limitar nuestra lógica para que solo se ejecute si DOMNode fue pasado a la función. Esto es importante ya que nuestra función se llamará cada vez que cambie el contenido de una entrada, es decir, si por alguna razón cometemos un error y no pasamos un DOMNode (o pasamos el valor incorrecto), estaríamos provocando errores de tiempo de ejecución con cada pulsación de tecla, no bueno.

/lib/autoResize.js

export default (DOMNode = {}, defaultHeight = 100) => {
  if (DOMNode) {
    const DOMNodeStyles = window.getComputedStyle(DOMNode);
    const paddingTop = parseInt(DOMNodeStyles?.getPropertyValue('padding-top') || 0, 10);
    const paddingBottom = parseInt(DOMNodeStyles?.getPropertyValue('padding-bottom') || 0, 10);

    DOMNode.style.height = `${defaultHeight}px`;
    DOMNode.style.height = `${DOMNode.scrollHeight - paddingTop - paddingBottom}px`;
  }
};

Arriba, agregamos la totalidad de nuestra lógica de tamaño automático (esto facilitará el paso).

Primero, debido a que estamos tratando con la altura, debemos anticipar cualquier relleno que nuestra entrada pueda haber establecido en su CSS. Para conseguirlo llamamos al window.getComputedStyle() función, pasando nuestro DOMNode para recuperar un objeto que contiene todos los estilos aplicados a nuestro <textarea></textarea> .

Con esos DOMNodeStyles , a continuación, queremos obtener el valor de relleno superior e inferior para el área de texto, ya que estos afectarán visualmente la altura de la entrada. Para conseguirlos llamamos al .getPropertyValue() método en el DOMNodeStyles objeto que acabamos de crear, pasando ya sea padding-top o padding-bottom .

Observe que pasamos la llamada a que método directamente en una llamada a parseInt() . Esto se debe a que el valor que obtenemos de este método es una cadena que contiene px (es decir, si nuestro padding-top fuera 10px obtendríamos "10px" ) y lo queremos como un entero simple como 10 .

Una vez que tengamos estos valores almacenados en paddingTop y paddingBottom , podemos pasar a ajustar la altura de nuestra área de texto.

Para hacerlo, necesitamos modificar directamente el style objeto del área de texto, configurando su height propiedad. Queremos hacer esto en dos pasos:primero, establecer la altura predeterminada y luego establecer la altura relativa al contenido actual del área de texto.

Queremos hacer esto porque necesitamos tener en cuenta que el usuario borra la entrada. Si esto sucede después de que la entrada haya tenido suficiente contenido para expandir la altura, al borrarla, la entrada conservará la altura establecida (ya que la altura de desplazamiento no ha cambiado).

Para establecer la altura, establecemos directamente el height propiedad en la entrada con DOMNode.style.height , estableciéndolo primero igual a la concatenación del defaultHeight variable y px como ${defaultHeight}px . A continuación, repetimos el mismo patrón, esta vez configurando la entrada en su scrollHeight actual , restando el paddingTop y paddingBottom valores que obtuvimos unas líneas más arriba y luego otra vez, concatenando el entero resultante con px .

¡Eso es todo! Ahora, usemos esto en nuestra interfaz de usuario y veamos cómo se conecta todo.

Usando la función de tamaño automático

Esta es la parte facil. Para simplificar las cosas, vamos a modificar un componente de IU existente creado para nosotros cuando ejecutamos joystick create app más temprano. Abramos el componente en /ui/pages/index/index.js y haz algunos cambios:

/ui/pages/index/index.js

import ui from '@joystick.js/ui';

const Index = ui.component({
  css: `
    label {
      display: block;
      font-size: 16px;
      margin-bottom: 10px;
    }

    textarea {
      display: block;
      resize: none;
      width: 300px;
      height: 100px;
      border: 1px solid #ddd;
      padding: 10px;
    }
  `,
  render: () => {
    return `
      <form>
        <label>What's your life story?</label>
        <textarea name="lifeStory"></textarea>
      </form>
    `;
  },
});

export default Index;

Reemplazando el contenido existente del archivo con el anterior, para comenzar queremos obtener el <textarea></textarea> queremos ajustar automáticamente la altura de renderizado en pantalla. Abajo en el render() función de nuestro componente, devolvemos una cadena de HTML que contiene un simple <form></form> elemento con un <label></label> y un <textearea></textarea> en él.

Justo encima de esto, para que nuestra interfaz de usuario se vea un poco mejor, hemos agregado algo de CSS para nuestro <label></label> y <textarea></textarea> elementos. Importante:presta atención al height propiedad para el área de texto que se establece en 100px . Esto es importante. Esto asegura que cuando nuestra entrada se represente por primera vez, su altura visual coincida con el defaultHeight estamos pasando a autoResize() .

/ui/pages/index/index.js

import ui from '@joystick.js/ui';
import autoResize from '../../../lib/autoResize';

const Index = ui.component({
  events: {
    'input textarea': (event) => {
      autoResize(event.target, 100);
    },
  },
  css: `...`,
  render: () => {
    return `
      <form>
        <label>What's your life story?</label>
        <textarea name="lifeStory"></textarea>
      </form>
    `;
  },
});

export default Index;

Ahora la parte importante. Arriba, hemos agregado un events propiedad a nuestro componente. En el objeto pasado aquí, hemos agregado un detector de eventos para el input evento en nuestro textarea elemento. Dentro de la función de devolución de llamada activada cuando se detecta el evento, usando el autoResize() función que importamos arriba, pasamos el event.target —o, nuestro <textarea></textarea> elemento:seguido de la altura predeterminada que queremos establecer en caso de que se borre el área de texto, 100 .

Eso lo hará. Ahora, si abrimos nuestro navegador a http://localhost:2600 (asegúrese de que su aplicación se esté ejecutando), deberíamos ver nuestro <textarea></textarea> expandir si el contenido supera la altura predeterminada.

Terminando

En este tutorial, aprendimos cómo conectar una función de tamaño automático que ajusta dinámicamente la altura de un área de texto en función de su contenido. Aprendimos a manipular la altura de una entrada sobre la marcha, usando su style atributo, asegurándose de tener en cuenta los cambios en el relleno. Finalmente, aprendimos cómo usar nuestra función en respuesta a un input evento en nuestro <textarea></textarea> .