Estilos Reactivos con Vue.js: Uso de Directivas Style y Class
Clase 12 de 23 • Curso de Vue.js: Introducción y Fundamentos
Contenido del curso
Clase 12 de 23 • Curso de Vue.js: Introducción y Fundamentos
Contenido del curso
Alvaro Eduardo Armijos Sarango
Markin Piero Pulache Guarniz
Phillip Leonardo Cabrera Medrano
Johanna Apure Canónico
Ricardo Ruiz Muñoz
Mateo Agudelo Echavarria
Rodrigo Ramos Xochiteotzin
Marcos Joel Sánchez López
José Alberto Ramírez Quiroz
Kenneth Leonel Cruz Ordoñez
JOSE FABIAN BONILLA GUZMAN
Julio Cesar Labrador Rosales
Luis Diego Aguilar Ruiz
Josue David
Cristobal Nyram
Brayhan Andres Jaramillo Castaño
Angelo Acevedo
Ximena Narváez
Emilena Saade
Yormi Altamiranda
Yenny Constanza Botero Martinez
Andrey Felipe Gomez Villa
Dannier Leonides Galicia Chinchilla
Samuel Mujica
Juan Francisco Rodríguez Riaño
Los estilos utilizados:
<style> html, body { height: 100vh; margin: 0; font-family: Arial, Helvetica, sans-serif; } #app, .container { display: flex; justify-content: center; align-items: center; flex-direction: column; width: 100%; height: 100%; } button { margin-top: 24px; border: none; background-color: white; padding: 8px 24px; border-radius: 12px; } .closed { background-color: #eca1a6; } .open { background-color: #b5e7a0; } </style>
gracias
Al usar ReactJs se me esta haciendo mas fá cil entender el funcionamiento básico de VueJs. El objeto data es parecido al hook useState, la propiedad watch a useEffect.
Tambien vengo de React :0
Otra manera de hacerlo sería crear un método dentro de methods obviamente, al cual podríamos llamar toggleDoor(), en el cual ponemos la lógica de "this.open = !this.open", y tras esto, escribir la lógica de los estilos css:
const vm = Vue.createApp({ data(){ return { text: "Puerta cerrada", open: false, styles: { backgroundColor: "#eca1a6", }, }; }, methods: { toggleDoor(){ this.open = !this.open; this.open ? this.styles.backgroundColor = "#b5e7a0" : this.styles.backgroundColor = "#eca1a6" } }, watch: { open(value){ if (value){ this.text = "Puerta abierta"; } else{ this.text = "Puerta cerrada"; } } }, template: ` <div class="container" :style="styles"> <h3>{{text}}</h3> <button @click="toggleDoor">{{open ? "Cerrar" : "Abrir"}}</button> </div> ` }).mount("#app");
Entonces, la pregunta sería : ¿Cuándo o en que casos usar computed o methods?
@mateo-agudelo.echavarria según tu necesidad de reactividad. Si quieres que la función actúe sólo determinado evento que tú definas (como picar un botón, por ejemplo) es más sencillo usar methods, pero si tu necesidad es que la función sea ejecutada cada que el valor sea cambiado es mejor usar computed porque está escuchando todo el tiempo.
Además de la falicidad que da vue para manejar estilos entre otras cosas. sigo aprendiendo de esos errores de novatos!! que hayan más errores para saber como resolverlos en el futuro.
Todo esto me recuerda al curso de WebComponents... aunque aqui en vue es mucho mas facil, hasta ahora :3
Maravilloso. Finalmente siento que me están entrando los conceptos básicos de Vue.
Gracias :)
estamos en condición similar, la teoría sine ejemplo se me dificulta muchísimo
Una necesidad común de data binding es manipular la lista de clases de un elemento y sus estilos en línea. Como ambos son atributos, podemos usar v-bind para manejarlos: solo necesitamos crear una cadena de texto con nuestras expresiones. Sin embargo, concatenar cadenas de texto puede llegar a ser incómodo y propenso a errores. Por esta razón, Vue proporciona mejoras cuando se utiliza v-bind conclass y style. Además de las cadenas de texto, las expresiones también pueden evaluar objetos o matrices.
fuente: https://es.vuejs.org/v2/guide/class-and-style.html
++Es la documentacion de Vue en español++
Creo que Vue es increible, yo he trabajado con React y la verdad me fue un poco dificil entender la reactividad al principio, pero con Vue es super facil de comprender.
Como creo que todos estan haciendo el reto de ponerle una imagen al codigo, quise intentarlo y este fue mi codigo (Aunque reutilice los estilos de la clase)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script src="https://unpkg.com/vue@next"></script> <main id="app"></main> <script> const vue = Vue.createApp({ data() { return { text: "La puerta esta cerrada", isOpen: false, } }, watch: { isOpen(current) { if(current) { this.text = "La puerta esta abierta" } else { this.text = "La puerta esta cerrada" } } }, computed: { image() { return this.isOpen ? "https://us.123rf.com/450wm/grebeshkovmaxim/grebeshkovmaxim1904/grebeshkovmaxim190400553/123026095-abrir-puerta-realista-aislada-en-sala-blanca.jpg?ver=6" : "https://previews.123rf.com/images/byzonda/byzonda1505/byzonda150500089/40505435-blanc-porte-ferm%C3%A9e-avec-cadre.jpg"; }, bgColor() { return this.isOpen ? 'open' : 'closed'; }, label() { return this.isOpen ? 'Close' : 'Open' } }, methods: { changeOpen() { return this.isOpen = !this.isOpen } }, template: ` <div class="container" :class="bgColor"> <h3>{{text}}</h3> <img :src="image"/> <button type="button" @click="changeOpen">{{ label }}</button> </div> ` }).mount('#app'); </script> <style> html, body { height: 100vh; margin: 0; font-family: Arial, Helvetica, sans-serif; } #app, .container { display: flex; justify-content: center; align-items: center; flex-direction: column; width: 100%; height: 100%; } button { margin-top: 24px; border: none; background-color: white; padding: 8px 24px; border-radius: 12px; } img { height: 400px; width: 400px; border-radius: 12px; } .open { background-color: rgb(100, 226, 100); } .closed { background-color: rgb(219, 102, 102); } </style> </body> </html>
Siendo honesto, las clases me han parecido una maravilla. Estoy entiendo super bien todos los conceptos, pero creo que tengo algo de ventaja por venir de React y de Angular. Vue.js con las directivas y el data binding es muy parecido a lo que tiene Angular. Aparte de tiene su parecido a los hooks de React con el data, funcionando con el useState, y el watch al useEffect, useMemo y así. Aunque creo que aun sin tener este contexto podría entenderle a la maestra, ya que sus ejemplos son super claros y muestra las distintas formas de como hacer destinas cosas. Esto se aprecia mucho y se que iré adquiriendo y adhiriendo estos conceptos y forma de desarrollar a medida que adquiera mas practica.
antes de seguir avanzando te recomiendo este articulo https://codingpotions.com/atributos-clases-estilos-dinamicos-vuejs
Hasta el momento me ha parecido muy bueno el curso, la explicación es excelente
Hola, vi un ejemplo e intente realizarlo yo mismo, aqui unas fotos y el codigo!
<style> html, body { height: 100vh; margin: 0; font-family: Arial, Helvetica, sans-serif; } #app, .container { display: flex; justify-content: center; align-items: center; flex-direction: column; width: 100%; height: 100%; } img { width: 200px; } button { margin-top: 24px; border: none; background-color: white; padding: 8px 24px; border-radius: 12px; } .closed { background-color: #eca1a6; } .open { background-color: #b5e7a0; } </style> <div id="app"></div> <script> const vm = Vue.createApp({ data() { return { text: "Puerta cerrada", open: false, img: "close.png" }; }, watch: { open(value) { if (value) { this.img = "open.png"; this.text = "Puerta abierta"; } else { this.img = "close.png"; this.text = "Puerta cerrada"; } } }, computed: { label() { return this.open ? "Cerrar" : "Abrir"; }, styles() { return this.open ? 'open' : 'closed'; } }, template: ` <div class="container" :class="styles"> <h3>{{ text }}</h3> <img :src="img"> <button @click="open = !open">{{ label }}</button> </div> ` }).mount("#app"); </script>
En mi caso use JQuery para añadir y remover las clases correspondientes, puse por defecto la clase closed y ya luego añadía y removía la correspondiente, el método container_styles_2 lo llamo luego del método que cambia el valor de open y me sirve correctamente
const vm = Vue.createApp({ data: () => { return { text: "Puerta Cerrada", open: false, }; }, computed: { action: function () { return this.open ? "Cerrar" : "Abrir"; }, container_styles: function() { return this.open ? ['open'] : ['closed']; } }, watch: { open: function(value) { this.text = value ? "Puerta Abierta" : "Puerta Cerrada"; } }, methods: { door: function () { this.open = !this.open; this.container_styles_2(); }, container_styles_2: function() { if (this.open) { $("#app .container").removeClass("closed"); $("#app .container").addClass("open"); } else { $("#app .container").removeClass("open"); $("#app .container").addClass("closed"); } } }, template: ` <div class="container closed"> <h3>{{ text }}</h3> <button v-on:click="door">{{ action }}</button> </div> ` }).mount("#app");
muy buena clase
VAle con diana estoy entendiedo Vue bien facil
les comparto el codigo con la hoja de estilos por separado
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="open_close_door.css"> <title>Document</title> </head> <body> <script src="https://unpkg.com/vue@3"></script> <div id="app"></div> <script> const vm = Vue.createApp( { data() { return { text: "Hey you!", open: false, }; }, watch:{ open(value){ if (value){ this.text= "La puerta está abierta, Pasa!"; }else { this.text= "La puerta está cerrada, Lo siento!"; } } }, computed:{ label(){ return this.open ? "Cerrar" : "Abrir"; }, //con la función computada para los estilos usamos las clases styles(){ return this.open ? [`open`] : [`close`]; } }, template: ` <div class="container" :class="styles"> <h2>{{ text }}</h2> <button @click="open = !open">{{ label }}</button> </div> ` }).mount("#app"); </script> </body> </html>
*{ box-sizing: border-box; margin: 0; padding: 0; } html{ font-size: 62.5%; font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif; } #app .container{ display: flex; align-content: center; justify-content: center; align-items: center; flex-direction: column; width: 100%; height: 700px; padding: 2rem; } h1{ margin-top: 2rem; margin-bottom: 2rem; font-size: 40px; } button{ width: 80px; height: 25px; border-radius: 1rem; color: white; font-weight: bold; background-color: black; } button:hover{ background-color: rgb(255, 246, 146); color: black; font-weight: bold; } .close{ background-color: rgb(156, 63, 63) ; } .open{ background-color: rgb(90, 168, 90); }
Mi aporte 2 ejemplos de la clase
<div class="container" :style="styles"> <h3>{{message}}</h3> <button @click = 'open =! open'>{{label}}</button> </div> <div class="container" :class="openDoor"> <h3>{{message}}</h3> <button @click = 'open =! open'>{{label}}</button> </div> data() { return { open: false, styles: { backgroundColor: '#eca1a6' } } }, watch: { open(value){ if(value){ this.message = 'Puerta abierta'; this.styles.backgroundColor = '#b5e7a0' }else{ this.message = 'Puerta cerrada'; this.styles.backgroundColor='#eca1a6' } } } computed: { label(){ return this.open ? 'cerrar' : 'Abrir' }, openDoor(){ return this.open ? ['open'] : ['closed']; }
Ya me había acostumbrado a videos cortos.
Estuve practicando un poco para poder usar los atributos style y class en dos puntos distintos del codigo, con watchers y propiedades computadas, creo que ambas tienen lo suyo:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <h1>Watchers</h1> <p> Los watchers en Vue.js son una poderosa herramienta que te permite observar y reaccionar ante cambios en una o más variables dentro de tu aplicación. A diferencia de las propiedades computadas, los watchers se enfocan en ejecutar acciones en respuesta a cambios, sin necesariamente modificar la interfaz del usuario o visualizar esos datos en el template. Se utilizan para realizar procesos en segundo plano, como enviar solicitudes a un backend o actualizar otros estados de la aplicación. </p> <ul> <li> Los watchers deberian ser sencillos </li> <li> El nombre del watcher debe coincidir con el de la variable que deseas observar. </li> <li> Los watchers reciben dos parámetros automáticamente: el valor actual y el valor anterior, lo que te permite tomar decisiones informadas en el proceso. </li> </ul> <div id="app"> </div> <script> const vm = Vue.createApp( { data() { return { door: "Puerta cerrada", openDoor: false, styles: { backgroundColor: '#eca1a6' } }; }, methods: {}, computed: { doorLabel() { return this.openDoor ? 'Cerrar' : 'Abrir' }, btnClass() { return this.openDoor ? ['closed'] : ['open'] } }, template: ` <div class="container" :style="styles"> <h3> {{door}} </h3> <div > <button :class="btnClass" @click="openDoor = !openDoor">{{doorLabel }}</button> </div> </div> `, watch: { openDoor(value) { this.door = value ? "Puerta abierta" : "Puerta cerrada" this.styles.backgroundColor = value ? "#b5e7a0" : "#eca1a6" } } } ).mount('#app'); </script> <style> html, body { height: 100vh; margin: 0; font-family: Arial, Helvetica, sans-serif; } #app, .container { display: flex; justify-content: center; align-items: center; flex-direction: column; width: 100%; height: 100%; } button { margin-top: 24px; border: none; padding: 8px 24px; border-radius: 12px; } .closed { background-color: #eca1a6; } .open { background-color: #b5e7a0; } </style> </body> </html>
yo siempre uso tailwind 😅
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://cdn.tailwindcss.com"></script> </head> <body> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <div id="app" class="w-full h-screen "></div> <script> const vm = Vue.createApp({ data() { return { cerrada: "https://cdn-icons-png.flaticon.com/512/32/32533.png", abierta: "https://cdn-icons-png.flaticon.com/512/2832/2832154.png", logo: "./logo/logo.png", mensaje: "La puerta estaba abierta y ahora esta cerrada", puerta: "https://cdn-icons-png.flaticon.com/512/32/32533.png", text_boton: "Abrir" } }, methods: { toggleEstado() { console.log("click"); if (this.text_boton === "Abrir") { this.text_boton = "Cerrar"; this.puerta = this.abierta; } else { this.text_boton = "Abrir"; this.puerta = this.cerrada; } } }, computed: { estilo() { return this.text_boton === "Abrir" ? "bg-red-300 flex flex-col justify-center items-center h-full" : "bg-blue-300 flex flex-col justify-center items-center h-full"; } }, watch: { text_boton(value, old) { text = "La quería " + old + " y ahora la quiero " + value; console.log(text); this.mensaje = text; } }, template: ` <div :class="estilo"> <div> <img :src="logo" alt="Pachoweb" class="w-64 mb-8"/> </div> <div class="mb-8 font-bold text-2xl"> <h1 class="text-white">{{mensaje}}</h1> </div> <div> <img class="w-64 mb-8" :src="puerta" alt="Cerrada" /> </div> <div> <button class="bg-white text-blue-500 font-bold py-2 px-4 rounded" v-on:click="toggleEstado()" >{{text_boton}}</button> </div> </div> ` }).mount('#app'); </script> </body> </html>