Migración de jQuery a Vue.js

El autor del artículo, cuya traducción publicamos hoy, cree que hay muchos más programadores en el mundo que, cuando necesitan desarrollar una aplicación web simple, recurren a jQuery . Por lo general, esto sucede cuando cierta página necesita estar equipada con funciones interactivas simples, pero usar algún tipo de marco de JavaScript para esto parece excesivo. Después de todo, estos son kilobytes de código innecesario, plantillas, herramientas para proyectos de construcción, herramientas para empaquetar módulos ... Al mismo tiempo, conectarse a una página jQuery usando un recurso CDN es tan fácil como desgranar peras.



Este artículo discutirá cómo traducir un proyecto creado usando jQuery a Vue.js. Este proyecto se creará en jQuery y luego se rediseñará con Vue. El autor del material quiere demostrar a todos que el uso de Vue, incluso en proyectos relativamente pequeños, no significa necesariamente un aumento excesivo en el tamaño del código de dichos proyectos y una gran carga adicional para el programador. Esto, por el contrario, con casi el mismo tamaño de código auxiliar que cuando se usa jQuery, le permite aumentar la productividad y mejorar la calidad de las aplicaciones.

Resumen del proyecto


Vamos a desarrollar una cuenta electrónica simple basada en esta plantilla de código abierto de Sparksuite.

A menudo, estos estudios de caso utilizan todo tipo de listas de tareas. Espero que una desviación de esta tradición haga que la historia sea más fresca y más interesante, y, al mismo tiempo, nuestra tarea será lo suficientemente difícil como para demostrar las ventajas de usar algo como Vue para desarrollar pequeños proyectos. El manual está diseñado para que todos, sin dificultades especiales, puedan reproducirlo y dominar los métodos de trabajo propuestos.

Aquí está la plantilla de cuenta con la que queremos trabajar.


Factura electrónica

Vamos a agregarle funciones interactivas, para que sea posible elegir un producto, su cantidad y precio unitario. Al cambiar los valores, se volverá a calcular el costo total de los bienes y el monto total del documento. Además, agregaremos un botón aquí que le permite insertar nuevas líneas vacías en la cuenta.

Modifiqué la plantilla convirtiendo el código HTML de la cadena vacía al siguiente formulario:

<tr class="item">  <td><input value="" /></td>  <td>$<input type="number" value="0" /></td>  <td><input type="number" value="1" /></td>  <td>$0.00</td> </tr> 

Desarrollo de proyectos JQuery


Primero, veamos cómo resolver nuestro problema usando jQuery.

 $('table').on('mouseup keyup', 'input[type=number]', calculateTotals); 

Conectamos el oyente del evento a la mesa. Este oyente llamará a la función calculateTotals cuando los valores correspondientes al costo unitario del producto o su cantidad cambien:

 function calculateTotals()  { const subtotals = $('.item').map((idx, val)  => calculateSubtotal(val)).get(); const total = subtotals.reduce((a, v)  => a + Number(v), 0); $('.total td:eq(1)').text(formatAsCurrency(total)); } 

La función toma las filas de la tabla y las recorre, pasando cada una de las filas a la función CalculateSubtotal y resumiendo los resultados. El resultado del cálculo cae en la constante constante. Como resultado, el monto total del documento se sustituye en el campo correspondiente de la cuenta.

 function calculateSubtotal(row) { const $row = $(row); const inputs = $row.find('input'); const subtotal = inputs[1].value * inputs[2].value; $row.find('td:last').text(formatAsCurrency(subtotal)); return subtotal; } 

En este código, tomamos referencias a todos los campos <input> presentes en la línea, luego multiplicamos los valores almacenados en el segundo y tercer campo para obtener el valor subtotal . Luego, este valor se inserta en la última celda de la fila. Formateamos este valor usando la función formatAsCurrency . Aquí está su código:

 function formatAsCurrency(amount) { return `$${Number(amount).toFixed(2)}`; } 

Además, tenemos una pequeña función auxiliar que utilizamos para garantizar la misma apariencia de los campos con los importes de los bienes y del documento en su conjunto. Es decir, debemos tener el signo $ delante de los números en estos campos, y que sean números decimales con dos decimales.

 $('.btn-add-row').on('click', () => { const $lastRow = $('.item:last'); const $newRow = $lastRow.clone(); $newRow.find('input').val(''); $newRow.find('td:last').text('$0.00'); $newRow.insertAfter($lastRow); $newRow.find('input:first').focus(); }); 

Y finalmente, tenemos un controlador de eventos para hacer clic en el botón Add row , que sirve para agregar una nueva línea al documento. Aquí tomamos la última fila de la tabla que contiene los datos del producto y hacemos una copia de la misma. Al mismo tiempo, insertamos datos estándar en los campos de esta nueva fila. Además, podemos ocuparnos de la conveniencia del usuario y enfocarnos en el primer campo de una nueva línea, lo que permitirá al usuario, inmediatamente después de agregar una nueva línea, comenzar a ingresar datos en su primer campo.

Aquí hay un ejemplo de trabajo de una cuenta cuyas características interactivas se implementan utilizando las herramientas jQuery.

Desventajas de la solución basada en jQuery


Preguntémonos cuáles son las desventajas del enfoque anterior, o más bien, cómo mejorar nuestro proyecto.

Es posible que haya oído hablar de nuevas bibliotecas, como Vue y React, que se dice que les permiten trabajar en un estilo declarativo en lugar de imperativo. Si observa el código jQuery anterior, está claro que se lee principalmente como un conjunto de instrucciones que describen la manipulación del DOM. El propósito de cada sección de este código, es decir, la respuesta a la pregunta de lo que hace, a menudo es bastante difícil de entender observando cómo lo hace. Por supuesto, puede aclarar las intenciones de los fragmentos de código utilizados al dividirlo en funciones con nombres cuidadosamente elegidos. Sin embargo, si deja este código por un tiempo y luego regresa a él nuevamente, resulta que para entenderlo, aún debe hacer algunos esfuerzos.

Otro problema con este código es que el estado de la aplicación se almacena en el DOM. La información sobre los productos que el usuario desea pedir existe solo como parte del marcado HTML en la interfaz de usuario. Si todo lo que necesitamos es generar datos en un solo lugar, entonces este problema no parece tan grave. Sin embargo, tan pronto como sea necesario mostrar estos datos en varios lugares de la aplicación, nos enfrentamos a la tarea de sincronizar los datos. Sin, como en nuestro caso, una fuente única de datos confiables, es muy difícil mantenerlos actualizados en toda la aplicación.

Al usar jQuery, nada nos impide almacenar el estado de la aplicación fuera del DOM y evitar el problema descrito anteriormente, las bibliotecas como Vue proporcionan características que ayudan a construir aplicaciones con una buena arquitectura. Estas bibliotecas ayudan al programador a escribir código más limpio y estructurado.

Traducción de proyectos en Vue


Ahora hablemos sobre cómo recrear la misma funcionalidad en Vue. Para aprovechar las capacidades de Vue, solo conecte esta biblioteca a una página web normal, tal como lo hace con jQuery. Es decir, no es necesario utilizar el sistema para empaquetar módulos o un transpilador; no es necesario dividir la aplicación en componentes y descomponer su código en archivos .vue.

Comenzamos a traducir el proyecto a Vue reemplazando el contenido de la <script> :

 <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> 

El siguiente paso es crear una nueva instancia de Vue:

 const app = new Vue({ el: 'table' }); 

El único parámetro para pasar al constructor de la nueva instancia de Vue es el . Este es un selector (el mismo que se usa en jQuery) que identifica la parte del documento que queremos controlar con Vue.

A Vue se le pueden asignar tareas de varios tamaños, desde administrar una página completa (en el caso de, por ejemplo, una aplicación de una sola página) hasta un pequeño fragmento encerrado en una <div> . En nuestro ejemplo, Vue será responsable de trabajar con la tabla HTML.

Datos


Agregue datos condicionales para tres líneas del documento a la instancia de Vue:

 const app = new Vue({ el: 'table', data: {   items: [     { description: 'Website design', quantity: 1, price: 300 },     { description: 'Hosting (3 months)', quantity: 1, price: 75 },     { description: 'Domain name (1 year)', quantity: 1, price: 10 },   ] } }); 

La propiedad de data es donde almacenamos el estado de la aplicación. El estado incluye no solo los datos con los que debería funcionar nuestra aplicación, sino también información sobre el estado de la interfaz de usuario (por ejemplo, qué sección de la aplicación, que consta de varias pestañas, está actualmente activa o si se minimiza un cierto widget, como un "acordeón", o expandido).

Vue ayuda a mantener el estado de la aplicación separado de su presentación (es decir, del DOM), y ayuda a almacenar centralmente el estado en un lugar, que es una fuente única de datos confiables.

Modificación de plantilla


Ahora configure la plantilla para que muestre los datos almacenados en el objeto de data . Como le dijimos al marco que queríamos trabajar con una tabla usando una instancia de Vue, podemos usar la sintaxis de la plantilla de Vue en el código HTML que describe esta tabla para decirle a Vue cómo representar la tabla y cómo usarla. a trabajar

Usando el atributo v-for , podemos inferir un bloque de código HTML para cada elemento de la matriz de items :

 <tr class="item" v-for="item in items"> </tr> 

Vue repetirá este marcado para cada elemento de la matriz (u objeto) que se pasa a v-for . Esto nos permite referirnos a cada elemento en el ciclo. En este caso, este elemento está representado por la variable del item . Dado que Vue supervisa las propiedades del objeto de data , el marco actualizará dinámicamente el marcado cuando cambie el contenido de la matriz de items . Todo lo que necesitamos hacer es modificar el estado agregando o eliminando elementos, y Vue actualizará automáticamente la interfaz de usuario.

Además, necesitamos agregar campos de entrada que el usuario pueda completar ingresando una descripción del producto, precio unitario, cantidad:

 <td><input v-model="item.description" /></td> <td>$<input type="number" v-model="item.price" /></td> <td><input type="number" v-model="item.quantity" /></td> <td>${{ item.price * item.quantity }}</td> 

Aquí usamos el atributo v-model para configurar el enlace de datos bidireccional entre campos de entrada y propiedades en el modelo de datos. Esto significa que cambiar los datos en los campos de entrada conducirá a su cambio en el modelo, y viceversa.

En la última celda, usamos llaves {{}} , las usamos para mostrar texto. Puede usar cualquier expresión de JavaScript que funcione entre paréntesis. En este caso, multiplicamos las dos propiedades del elemento y sacamos lo que sucedió. Nuevamente, Vue supervisa el modelo de datos; cambiar cualquier propiedad contará automáticamente la expresión.

Eventos y métodos


Ahora tenemos una plantilla lista para mostrar la colección de items y nos enfrentamos a la pregunta de cómo agregar nuevas filas a la tabla. Dado que Vue generará todo lo que está en la matriz de items en la página, para mostrar una cadena vacía en la página, es suficiente pasar el objeto Vue con cualquier valor que deba estar presente en la matriz de items .

Para crear una función a la que se pueda acceder desde la plantilla, debe pasar esta función a la instancia de Vue como una propiedad del objeto de methods :

 const app = new Vue({ // ... methods: {   myMethod() {} }, // ... }) 

addRow método addRow , al que se puede llamar para agregar un nuevo elemento a la matriz de items :

 methods: { addRow() {   this.items.push({ description: '', quantity: 1, price: 0 }); }, }, 

Tenga en cuenta que cualquier método que creamos estará automáticamente vinculado a la instancia de Vue, lo que nos permitirá acceder a las propiedades del objeto de data y a otros métodos como propiedades de this partir de estos métodos.

Entonces ahora tenemos un método. ¿Cómo llamarlo haciendo clic en el botón Add row ? Para agregar oyentes de eventos a los controles en una plantilla, Vue usa la sintaxis v-on:event-name .

 <button class="btn-add-row" @click="addRow">Add row</button> 

Vue también proporciona un acceso directo para v-on : construct, que se parece a @ . Se utiliza en el fragmento de código anterior. Puede usar cualquier método de la instancia de Vue como controlador de eventos.

Propiedades calculadas


Ahora solo tenemos que retirar el monto total del documento en la parte inferior de la factura. Esto se puede hacer en la plantilla misma. Como ya se mencionó, Vue le permite colocar cualquier expresión JS que funcione en construcciones de llaves. Sin embargo, es mucho mejor adherirse a un enfoque en el que solo la lógica muy simple y nada más se almacena en la plantilla. Si la lógica se separa de la plantilla, el código será más limpio, será más fácil de probar.

Para este propósito, podemos usar el método habitual, pero creo que en este caso, la llamada propiedad calculada es la mejor para nosotros. Trabajar con tales propiedades se parece al trabajo anterior con métodos. Es decir, para crear tales propiedades, se pasa un objeto computed a la computed Vue, que contiene funciones cuyos resultados de ejecución queremos usar en la plantilla:

 const app = new Vue({ // ... computed: {   total() {     return this.items.reduce((acc, item) => acc + (item.price * item.quantity), 0);   } } }); 

Ahora se puede hacer referencia a la propiedad calculada desde la plantilla:

 <tr class="total"> <td colspan="3"></td> <td>Total: ${{ total }}</td> 

Como habrá notado, las propiedades calculadas en la plantilla funcionan como si fueran datos. En este caso, no necesita "llamar" a nada en la plantilla. El uso de propiedades calculadas tiene otra ventaja. Vue es un sistema bastante inteligente, almacena en caché los valores devueltos y los vuelve a contar solo si cambian las propiedades de las que dependen los valores de las propiedades calculadas.

Si usáramos el método para calcular la cantidad total del documento, los cálculos se realizarían cada vez que se imprimiera la plantilla. Pero, dado que usamos la propiedad calculada, la cantidad total se recalcula solo cuando se cambian los valores de quantity o price en las filas de la tabla.

Filtros


Es posible que haya notado que hay un pequeño error en la implementación de nuestro proyecto creado usando Vue. Consiste en el hecho de que cuando los precios de bienes individuales se expresan en números enteros, los valores calculados de las cantidades totales en filas y la cantidad total en el documento se muestran como valores en dólares enteros, sin centavos. Nos gustaría, como en el ejemplo de jQuery, estos números siempre contienen dos decimales.

En lugar de modificar el código responsable de calcular el valor total de la línea y el código que calcula la cantidad total del documento, podemos aprovechar las prácticas capacidades de formato de datos de Vue. Se trata de filtros.

Como probablemente ya haya entendido, para crear un filtro, es suficiente pasar un objeto ( filters en este caso) con la clave correspondiente a la instancia de Vue:

 const app = new Vue({ // ... filters: {   currency(value) {     return value.toFixed(2);   } } }); 

Aquí hemos creado un filtro muy simple llamado currency . Llama a la función toFixed(2) por el valor numérico que se le pasa y devuelve el resultado. Puede usar este filtro en la plantilla de la siguiente manera:

 <td>Total: ${{ total | currency }}</td> 

Aquí está la implementación completa de nuestro proyecto en Vue.

Resumen


Si compara dos versiones del proyecto, una creada con jQuery y la segunda escrita en Vue, notará los siguientes puntos fuertes de la aplicación basada en Vue:

  • Una separación clara entre la interfaz de usuario, la lógica y los datos que controlan la interfaz. El código es más claro, será más fácil de probar.
  • Una descripción declarativa de la interfaz. El programador solo necesita ocuparse de cómo describir lo que quiere ver en la pantalla, y no cómo acceder al DOM para darle a la página de la aplicación el aspecto deseado.

Las bibliotecas Vue y jQuery son casi del mismo tamaño (en kilobytes). Por supuesto, el tamaño de jQuery puede reducirse utilizando nuestro propio ensamblaje de biblioteca, pero incluso en proyectos relativamente simples, como nuestro ejemplo de una cuenta electrónica, creo que la facilidad de desarrollo y la legibilidad del código justifican un ligero aumento en el tamaño de la aplicación.

Además, las capacidades de Vue son mucho más amplias que las que describimos aquí. La fortaleza de este marco reside en el hecho de que le permite crear componentes de interfaz de usuario modulares y reutilizables a partir de los cuales puede construir aplicaciones cliente complejas.

Si está interesado en el tema del desarrollo de aplicaciones web en Vue, eche un vistazo a este material . Además, si está considerando mover proyectos de JS puro a Vue, aquí está nuestra publicación reciente sobre este tema.

Estimados lectores! ¿Usas jQuery? Y, si lo usa, ¿planea cambiar esta biblioteca a otra, por ejemplo, a Vue?

Source: https://habr.com/ru/post/es414073/


All Articles