Pasar de JavaScript básico a un componente Vue reutilizable

Índice
  1. Plantillas y estilos
  2. Constantes y variables
  3. Usar datos y propiedades calculadas en la plantilla
  4. Métodos y enlaces del ciclo de vida de los componentes.
  5. ¡Eso es un envoltorio!

Recientemente escribí un artículo que explica cómo se puede crear un temporizador de cuenta regresiva usando HTML, CSS y JavaScript. Ahora, veamos cómo podemos convertirlo en un componente reutilizable transfiriéndolo a Vue utilizando las características básicas que proporciona el marco.

¿Por qué hacer esto? Pues hay pocas razones, pero destacan dos en particular:

  • Mantener la interfaz de usuario sincronizada con el estado del temporizador: si observa el código de la primera publicación, todo reside en la función timerInterval, sobre todo la gestión del estado. Cada vez que se ejecuta (cada segundo), necesitamos encontrar manualmente el elemento adecuado en nuestro documento (ya sea la etiqueta de tiempo o la ruta de tiempo restante o lo que sea) y cambiar su valor o un atributo. Vue viene con una sintaxis de plantilla basada en HTML que le permite vincular de forma declarativa el DOM renderizado a los datos de la instancia de Vue subyacente. Esto elimina toda la carga de encontrar y actualiza los elementos adecuados de la interfaz de usuario para que podamos confiar únicamente en las propiedades de la instancia del componente.
  • Tener un componente altamente reutilizable: el ejemplo original funciona bien cuando solo hay un temporizador en nuestro documento, pero imagina que quieres agregar otro. ¡UPS! Dependemos del ID del elemento para realizar nuestras acciones y usar el mismo ID en varias instancias impediría que funcionen de forma independiente. Eso significa que tendríamos que asignar diferentes ID para cada temporizador. Si creamos un componente Vue, toda su lógica se encapsula y se conecta a esa instancia específica del componente. ¡Podemos crear fácilmente 10, 20, 1000 temporizadores en un solo documento sin cambiar una sola línea en el componente!

Aquí está el mismo temporizador que creamos juntos en la última publicación, pero en Vue.

Plantillas y estilos

De los documentos de Vue :

Vue utiliza una sintaxis de plantilla basada en HTML que le permite vincular de forma declarativa el DOM renderizado a los datos de la instancia de Vue subyacente. Todas las plantillas de Vue.js son HTML válidas que pueden ser analizadas por navegadores y analizadores de HTML que cumplan con las especificaciones.

Creemos nuestro componente abriendo un nuevo archivo llamado BaseTimer.vue. Aquí está la estructura básica que necesitamos para eso:

// Our template markup will go heretemplate// .../template// Our functional scripts will go herescript// .../script// Our styling will go herestyle// .../style

En este paso, nos concentraremos en las secciones templatey . styleMovamos nuestra plantilla de temporizador a la templatesección y todo nuestro CSS a stylela sección. El marcado consiste principalmente en SVG y podemos usar exactamente el mismo código que usamos en el primer artículo.

template  // The wrapper for the timer  div    // This all comes from the first article    svg viewBox="0 0 100 100"       g        circle cx="50" cy="50" r="45"/circle        path                   stroke-dasharray="283"                   d="            M 50, 50            m -45, 0            a 45,45 0 1,0 90,0            a 45,45 0 1,0 -90,0          "        /path      /g    /svg    // The label showing the remaining time    span                    ${formatTime(timeLeft)}    /span  /div/template// "scoped" means these styles will not leak out to other elements on the pagestyle scoped.base-timer {  position: relative;  width: 100px;  height: 100px;}/style

Echemos un vistazo a la plantilla que acabamos de copiar para identificar dónde podemos usar nuestro marco. Hay algunas partes que son responsables de hacer que nuestro temporizador cuente el tiempo y muestre el tiempo restante.

  • stroke-dasharray: valor pasado al pathelemento SVG que es responsable de mantener el tiempo restante.
  • remainingPathColor: Una clase CSS responsable de cambiar el color del anillo circular del temporizador, lo que proporciona una forma de indicar visualmente que el tiempo se está acabando.
  • formatTime(timeLeft): Un valor responsable de cuánto mostrar tiempo queda dentro del temporizador.

Podemos controlar nuestro temporizador manipulando esos valores.

Constantes y variables

Bien, vayamos a nuestra scriptsección y veamos qué nos ofrece Vue listo para usar para hacernos la vida más fácil. Una cosa que nos permite hacer es definir nuestras constantes por adelantado, lo que las mantiene en el ámbito del componente.

En la última publicación, dedicamos un poco de tiempo a ajustar el stroke-dasharrayvalor para asegurarnos de que la animación de la capa superior del temporizador (el anillo que se anima y cambia de color a medida que avanza el tiempo) esté perfectamente alineada con su capa inferior. (el anillo gris que indica el pasado). tiempo). También definimos “umbrales” para cuándo la capa superior debería cambiar de color (naranja a los 10 segundos restantes y rojo a los cinco segundos). También creamos constantes para esos colores.

Podemos moverlos todos directamente a la scriptsección:

script// A value we had to play with a bit to get rightconst FULL_DASH_ARRAY = 283;// When the timer should change from green to orangeconst WARNING_THRESHOLD = 10;// When the timer should change from orange to redconst ALERT_THRESHOLD = 5;// The actual colors to use at the info, warning and alert threshholdsconst COLOR_CODES = {  info: {    color: "green"  },  warning: {    color: "orange",    threshold: WARNING_THRESHOLD  },  alert: {    color: "red",    threshold: ALERT_THRESHOLD  }};// The timer's starting pointconst TIME_LIMIT = 20;/script

Ahora, echemos un vistazo a nuestras variables:

let timePassed = 0;let timeLeft = TIME_LIMIT;let timerInterval = null;let remainingPathColor = COLOR_CODES.info.color;

Podemos identificar dos tipos diferentes de variables aquí:

  1. Variables en las que los valores se reasignan directamente en nuestros métodos:
    • timerInterval: Cambia cuando iniciamos o paramos el cronómetro
    • timePassed: Cambia cada segundo cuando el temporizador está funcionando
  2. Variables en las que los valores cambian cuando cambian otras variables:
    • timeLeft: Cambia cuando el valor de timePassedlos cambios
    • remainingPathColor: Cambia cuando el valor de timeLeftsupera el umbral especificado

Es identificar esencial esa diferencia entre esos dos tipos, ya que nos permite utilizar diferentes características del marco. Repasemos cada uno de los tipos por separado.

Variables en las que se reasignan valores directamente

Pensemos en lo que queremos que suceda cuando cambiemos el timePassedvalor. Queremos calcular cuánto tiempo queda, comprobar si debemos cambiar el color del anillo superior y activar el renderizado en una parte de nuestra vista con nuevos valores.

Vue viene con su propio sistema de reactividad que actualiza la vista para que coincida con los nuevos valores de propiedades específicas. Para agregar una propiedad al sistema de reactividad de Vue, necesitamos declarar esa propiedad en un dataobjeto de nuestro componente. Al hacer esto, Vue creará un captador y un definidor para cada propiedad que rastreará los cambios en esa propiedad y responderá en consecuencia.

script// Same as beforeexport default {  data() {    return {      timePassed: 0,      timerInterval: null    };  }/script

Hay dos cosas importantes que debemos recordar.

  1. Necesitamos declarar todas las variables reactivas en nuestro dataobjeto por adelantado. Eso significa que si sabemos que existirá una variable pero no sabemos cuál será el valor, aún debemos declararla con algún valor. Si olvidamos declararlo datano será reactivo, incluso si se agrega más tarde.
  2. Al declarar nuestro dataobjeto de opción, siempre necesitamos devolver una nueva instancia de objeto (usando return). Esto es vital porque, si no seguimos esta regla, las propiedades declaradas se compartirán entre todas las instancias del componente.

Puedes ver ese segundo número en acción:

Variables en las que los valores cambian cuando otras variables cambian

Estas variables dependen del valor de otra variable. Por ejemplo, timeLeftse basa exclusivamente en timePassed. En nuestro ejemplo original que usa JavaScript básico, estábamos calculando ese valor en el intervalo que era responsable de cambiar el valor de timePassed. Con Vue podemos extraer ese valor a una computedpropiedad.

Una computedpropiedad es una función que devuelve un valor. Estos valores están vinculados a los valores de dependencia y solo se actualizan cuando es necesario. Aún más importante, computedlas propiedades se almacenan en caché, lo que significa que recuerdan los valores de los que computeddependen la propiedad y calculan el nuevo valor solo si el valor de la propiedad dependiente cambió. Si el valor no cambia, se devuelve el valor previamente almacenado en caché.

script// Same as beforecomputed: {    timeLeft() {      return TIME_LIMIT - this.timePassed;    }  }}/script

La función pasada a la computedpropiedad debe ser una función pura . No puede causar ningún efecto secundario y debe devolver un valor. Además, el valor de salida solo debe depender de los valores pasados ​​a la función.

Ahora podemos trasladar más lógicas a computedlas propiedades:

  • circleDasharray: Esto devuelve un valor previamente calculado en el setCircleDasharraymétodo.
  • formattedTimeLeft: Esto devuelve un valor del formatTimemétodo.
  • timeFraction: Esta es una abstracción del calculateTimeFractionmétodo.
  • remainingPathColor: Esta es una abstracción del setRemainingPathColormétodo.
script// Same as beforecomputed: {    circleDasharray() {      return `${(this.timeFraction * FULL_DASH_ARRAY).toFixed(0)} 283`;    },    formattedTimeLeft() {      const timeLeft = this.timeLeft;      const minutes = Math.floor(timeLeft / 60);      let seconds = timeLeft % 60;      if (seconds  10) {        seconds = `0${seconds}`;      }      return `${minutes}:${seconds}`;    },    timeLeft() {      return TIME_LIMIT - this.timePassed;    },    timeFraction() {      const rawTimeFraction = this.timeLeft / TIME_LIMIT;      return rawTimeFraction - (1 / TIME_LIMIT) * (1 - rawTimeFraction);    },    remainingPathColor() {      const { alert, warning, info } = COLOR_CODES;      if (this.timeLeft = alert.threshold) {        return alert.color;      } else if (this.timeLeft = warning.threshold) {        return warning.color;      } else {        return info.color;      }    }  }/script

¡Ahora tenemos todos los valores que necesitamos! Pero ahora necesitamos utilizarlos en nuestra plantilla.

Usar datos y propiedades calculadas en la plantilla

Aquí es donde lo dejamos con nuestra plantilla:

template  div    svg viewBox="0 0 100 100"       g        circle cx="50" cy="50" r="45"/circle        path                   stroke-dasharray="283"                   d="            M 50, 50            m -45, 0            a 45,45 0 1,0 90,0            a 45,45 0 1,0 -90,0          "        /path      /g    /svg    span                      ${formatTime(timeLeft)}    /span  /div/template

Empecemos con formatTime(timeLeft). ¿Cómo podemos vincular dinámicamente el valor representado a nuestra formattedTimeLeftcomputedpropiedad?

Vue utiliza una sintaxis de plantilla basada en HTML que nos permite vincular declarativamente el DOM renderizado a los datos subyacentes de la instancia de Vue. Eso significa que todas las propiedades están disponibles en la sección de plantilla. Para representar a cualquiera de ellos, utilizamos la interpolación de texto utilizando la sintaxis “Bigote” (dobles llaves o {{ }}).

span    {{ formattedTimeLeft }} /span

El próximo será stroke-dasharray. Podemos ver que no queremos representar ese valor. En cambio, queremos cambiar el valor del pathatributo. Moustache no se puede utilizar dentro de los atributos HTML, ¡pero no temas! Vue viene con otra forma: la v-binddirectiva. Podemos vincular un valor a un atributo como este:

path  v-bind:stroke-dasharray="circleDasharray"/path

Para facilitar el uso de esa directiva, también podemos utilizar una taquigrafía .

path  :stroke-dasharray="circleDasharray"/path

El último es remainingPathColor, que agrega una clase adecuada a un elemento. Podemos hacerlo usando la misma v-binddirectiva anterior, pero asignando el valor al classatributo de un elemento.

path  :class="remainingPathColor"/path

Echemos un vistazo a nuestra plantilla después de los cambios.

template  div    svg viewBox="0 0 100 100"       g        circle cx="50" cy="50" r="45"/circle        path          :stroke-dasharray="circleDasharray"                   :class="remainingPathColor"          d="            M 50, 50            m -45, 0            a 45,45 0 1,0 90,0            a 45,45 0 1,0 -90,0          "        /path      /g    /svg    span{{ formattedTimeLeft }}/span  /div/template

Tenemos nuestra plantilla lista, movimos todas las variables a datao computedy eliminamos la mayoría de los métodos creando computedlas propiedades correspondientes. Sin embargo, todavía nos falta una parte vital: tenemos que poner en marcha nuestro cronómetro.

Métodos y enlaces del ciclo de vida de los componentes.

Si observamos nuestro startTimermétodo, podemos ver que todos los cálculos, cambios en atributos, etc. ocurren en el intervalo.

function startTimer() {  timerInterval = setInterval(() = {    timePassed = timePassed += 1;    timeLeft = TIME_LIMIT - timePassed;    document.getElementById("base-timer-label").innerHTML = formatTime(      timeLeft    );    setCircleDasharray();    setRemainingPathColor(timeLeft);    if (timeLeft === 0) {      onTimesUp();    }  }, 1000);}

Como ya hemos movido toda esa lógica a la computedpropiedad, todo lo que tenemos que hacer timerIntervales cambiar el valor de timePassed; el resto sucederá mágicamente en las computedpropiedades.

script// Same as beforemethods: {  startTimer() {    this.timerInterval = setInterval(() = (this.timePassed += 1), 1000);  }}/script

Tenemos el método listo, pero todavía no lo llamamos en ningún lado. Cada componente de Vue viene con una serie de ganchos que nos permiten ejecutar una lógica específica dentro de un período específico del ciclo de vida del componente. Estos se denominan ganchos del ciclo de vida . En nuestro caso, queremos llamar a nuestro método inmediatamente cuando se carga el componente. Eso hace que mountedel ciclo de vida enganche lo que queremos.

script// Same as beforemounted() {  this.startTimer();},// Same methods as before/script 

Eso es todo, ¡simplemente convertimos nuestro temporizador en un componente consistente y reutilizable usando Vue!

Digamos que ahora queremos usar este componente en otro componente. Eso requiere algunas cosas:

  1. Primero, importamos el componente.
  2. A continuación, registramos el componente.
  3. Finalmente, creamos una instancia del componente en la plantilla.
// App.vueimport BaseTimer from "./components/BaseTimer"export default {  components: {    BaseTimer  }};

¡Eso es un envoltorio!

Este ejemplo muestra cómo podemos mover un componente de JavaScript básico a un marco de trabajo front-end basado en componentes, como Vue.

Ahora podemos tratar el temporizador como un componente independiente donde todo el marcado, la lógica y el estilo están contenidos de una manera que no se filtrará ni entrará en conflicto con otros elementos. Los componentes suelen ser hijos de un componente principal más grande que ensambla varios componentes juntos, como un formulario o tal vez una tarjeta. donde se puede acceder y compartir las propiedades del padre. Aquí hay un ejemplo del componente del temporizador donde recibe órdenes de un componente principal.

¡Espero haberte interesado en Vue y el poder de los componentes! Te recomiendo que vayas a los documentos de Vue para obtener una descripción más detallada de las funciones que utilizamos en nuestro ejemplo. ¡Hay tantas cosas que Vue puede hacer!

SUSCRÍBETE A NUESTRO BOLETÍN 
No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir

Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion