- Notifications
You must be signed in to change notification settings - Fork0
Curso-VUE/1-primeros-pasos
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
- Introducción
- Hola Mundo
- Primer componente
- Propiedades calculadas
- Métodos
- Data binding con v-model
- Data binding con v-model y arrays
- Eventos
- Acceso a datos del componente padre
- Acceso a datos del componente hijo utilizando referencias
- Acceso a datos del componente hijo utilizando referencias
- Introducción a fomularios. Login básico
- Bucles con v-for
- Condicionales con v-if
- Slots. Ejemplo de layout
- Watchers
- Computed properties con getters y setters
- Carga de componentes dinámicos concomponent
- Mixins
- Directivas (foco a input)
- Directivas (aplicar estilos)
- Filtros
- Plugins
- Props
- Props VS Data y reactividad
El core de vue es el siguiente:
Template:
<divid="app"> {{ message }}</div>
Componente:
varapp=newVue({el:'#app',data:{message:'Hello Vue!'}});
En esta introducción vamos a utilizar directamente el CDN de vue. Creamos unindex.html e incluimos el script del cdn en su head:
<!DOCTYPE html><html><head><metacharset="utf-8"><title>Vuejs 2</title><scriptsrc="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script></head><body></body></html>
En elbody del HTML incluimos el template y el script con el código:
...<body><divid="app"> {{ msg }}</div><script>newVue({el:'#app',data(){return{msg:'Hola Mundo'}}});</script></body>....
Para esta introducción vamos a reutilizar el archivoindex.html anterior, en cargaremos el componente en la secciónhead del HTML dentro de etiquetasscript y visualizaremos los distintos componentes que vayamos generando dentro deldiv con.
Los nuevos componentes se definirán dentro de la carpeta components en archivos.js.
Generamos un nuevo componentemessage.js.
Vue.component('message',{data(){return{message:'Hola Mundo';}},template:` <div> <h1>Componente Message</h1> <p>{{message}}</p> </div> `});
Son propiedades generadas a partir de otras propiedades del componente.
Creamos un nuevo componentecomputed-properties:
Vue.component('computed-properties',{data(){return{name:'Israel',surname:'Parra'}},computed:{fullName(){return`${this.name}${this.surname}`;}},template:` <div> <h2>Computed Properties</h2> <p>{{fullName}}</p> </div> `});
Los métodos son funciones que ejecutan en el componente y que son lanzadas por eventos del mismo.
Creamos un nuevo componentemethods.js
Vue.component('methods',{data(){return{name:'Israel',surname:'Parra'}},computed:{fullName(){return`${this.name}${this.surname}`;}},methods:{hello(){alert(this.fullName);}},template:` <div> <h2>Ejecutar métodos con Vuejs</h2> <p @click="hello">Pulsa aquí para ejecutar el método hello</p> </div> `});
Data binding permite que una variable almacene los cambios realizados sobre ella desde el template.
Creamos un nuevo componentevmodel.js.
Vue.component('vmodel',{data(){return{framework:'Vuejs 2'}},template:` <div> <h2>Trabajando con v-model</h2> <input v-model="framework" /> <p>El framework escogido es: {{ framework }}</p> </div> `});
Comprobamos como el valor de framework funciona como value del input y cuando se modifica queda reflejado en el párrafo siguiente.
Creamos un nuevo componentevmodel-checkboxes.js.
Vue.component('vmodel-checkboxes',{data(){return{frameworks:[]}},template:` <div> <h2>vmodel con arrays</h2> <input type="checkbox" value="VueJS 2" v-model="frameworks" /> <label for="vuejs2">VueJS 2</label> <input type="checkbox" value="Angular" v-model="frameworks" /> <label for="angular">Angular</label> <input type="checkbox" value="ReactJS" v-model="frameworks" /> <label for="reactjs">ReactJS</label> <p>Frameworks seleccionados: {{ frameworks }}</p> </div> `});
Desmarcando y marcando los checkboxes podemos ver como se modifica el contenido deframeworks.
Los eventos se emiten siempre del componente hijo al componente padre.
Creamos un nuevo componenteemit.js. En el template especificamos el nombre del evento que vamos a emitir y el parámetro que enviamos al componente padre.El nombre del evento debe de estár en minúsculas
Vue.component('emit',{data(){return{carBrand:'Toyota'}},template:` <div> <h2>Emitir enventos con Vuejs 2</h2> <p @click="$emit('show_car_brand', carBrand)"> Pulsa aqui para emitir un evento a la instancia ROOT de Vuejs </p> </div> `});
En este caso, en el componente padre debemos espedificar el evento:
<head> ...<scriptsrc="components/event.js"></script> ...</head><body> ...<emit@show_car_brand="showCarBrandFromEmitCmp"></emit> ...</body>
Definimos la función showCarBrandFromEmitCmp en el script que instancia el componente root enindex.html:
<script>newVue({el:'#app',methods:{showCarBrandFromEmitCmp(carBrand){alert(carBrand)}}})</script>
Creamos enindex.html, en la instancia del componente root una variable a la que queremos acceder desde un componente hijo:
...newVue({el:'#app',data(){return{appName:'Iniciando con VueJS 2'}},methods:{...
Creamos un nuevo componenteparent-data.js:
Vue.component('parent-data',{template:` <div> <h2>Acceso a datos del cmp padre desde el cmp hijo</h2> <p>{{ $parent.appName }}</p> </div> `});
De esta forma, utilizando$parent.appName
estamos accediendo desde el componente hijo a la variable appName del componente padre. Pueden concatenrase varias llamadas a$parent.parent.parent...
para subir varios niveles.
Creamos un nuevo componentechild-data.js en donde la variable cmpName será la que recuperaremos del componente padre:
Vue.component('child-data',{data(){return{cmpName:'Child Data CMP'}},template:` <div> <h2>Acceso a datos del cmp hijo desde el cmp padre</h2> </div> `});
Enindex.html cargamos el nuevo componente y creamos la referencia:
<head> ...<scriptsrc="components/child-data.js"></script> ...</head><body> ...<child-dataref="childData"></child-data> ...</body>
En la instacia del componente root definimos el métodomounted que se ejecutará cuando se haya montado el componente root, y desde él accedemos a la variable del componente hijo.
...mounted(){constcmpName=this.$refs.childData.cmpName;console.log(cmpName)},...
Creamos un nuevo componentechild-methods.js:
Vue.component('child-methods',{data(){return{cmpName:'Child Methods CMP'}},methods:{showCmpName(){console.log(this.cmpName)}},template:` <div> <h2>Acceso a métodods del cmp hijo desde el cmp padre</h2> </div> `});
Enindex.html cargamos el nuevo componente y creamos la referencia:
<head> ...<scriptsrc="components/child-methods.js"></script> ...</head><body> ...<child-methodsref="childMethods"></child-methods> ...</body>
En el métodomounted invocamos el método del componente hijo.
...mounted(){...setTimeout(()=>{this.$refs.childMethods.showCmpName()},1000);},...
Creamos un nuevo componentelogin-form.
Los datos del componente serán el usuario (email y contraseña) y el estado del login:
data(){return{logged:false,user:{email:'',password:''}}},
El método login cambiárá el estado dellogged.
methods:{login(){this.logged=this.user.email==='test@m.com'&&this.user.password==="1234"}},
En el template hacemos uso de la directiva v-show para mostrar o no contenido html en función de una condición.
template: `<div><h2>Formulario de login</h2><pv-show="logged"style="background: green; color: white"> Has iniciado sesión con los datos: {{ user }}</p><form@submit.prevent="login"><inputautocomplete="off"type="email"v-model="user.email"name="email"/><inputtype="password"v-model="user.password"name="password"/><inputtype="submit"value="Iniciar sesión"/></form></div> `
Creamos un nuevo componenteloops.js.
Vue.component('loops',{data(){return{frameworks:[{id:1,name:"VueJS 2"},{id:2,name:"ReactJS"},{id:3,name:"Ember"},{id:4,name:"AdonisJS"},{id:5,name:"Angular"},{id:6,name:"Laravel"}]}},template:` <div v-if="frameworks.length"> <h2>Bucles con v-for</h2> <ul> <li v-for="framework in frameworks" :key="framework.id"> {{ framework.name }} </li> </ul> </div> `})
En este componente utilizamos nuevos conceptos:
- Directiva v-for para iterar en un elemento HTML.
- Directiva v-if para no mostrar el elemento en el caso en el que no haya datos sobre los que iterar.
- Como buena práctica, debemos siempre en los elementos sobre los que iteramos establecer una key única. Utilizamos:key para indicar que la key es una variable.
Generamos un nuevo componenteconditionals.js.
Vue.component('conditionals',{data(){return{age:20}},template:` <div> <h2>Condicionales con v-if</h2> <input v-model="age" /> <p v-if="age < 18">Menor de edad</p> <p v-else-if="age >=18 && age < 30">Mayor de edad y menor de 30</p> <p v-else-if="age >=30 && age < 65">Mayor de 30 y menor de 65</p> <p v-else>Estas jubilad@</p> </div> `})
En función del valor que se introduzca en el input se mostrará uno u otro mensaje.
Los slots permiten definir layouts en donde se pueda sobreesribir partes del cógigo.
Generamos un nuevo componenteslots.js.
Vue.component('slots',{template:` <div> <h2>Slots, ejemplo de layout</h2> <div> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div> </div> `});
En elindex.html redefinimos el contenido del template de la siguiente forma:
<slots><p>Parrafo 1 del slot</p><templateslot="header"><h3>Header del layout con slots</h3></template><p>Parrafo 2 del slot</p><templateslot="footer"><h3>Footer del layout con slots</h3></template></slots>
Todo lo que esté fuera de los distintos templates formará parte de lo definido con la etiqueta slot en el template sin asignarle nombre (en nuestro caso dentro de las etiquetas main).
Los watchers son una zona de un componente que permite revisar de forma constante los cambios en un dato.
Generamos un nuevo componentewatchers.js:
Vue.component('watchers',{data(){return{user:null,oldUser:null}},template:` <div> <h2>Watchers con VueJS 2</h2> <p>Nuevo usuario: {{ user }}</p> <p>Anterior usuario: {{ oldUser }}</p> <button @click="randomUser">Obtener un usuario aleatorio</button> </div> `})
Establecemos un método que permita obtener por fetch un usuario random y actualizar el valor deuser:
...methods:{asyncrandomUser(){try{constdata=awaitfetch('https://randomuser.me/api/');constjson=awaitdata.json();constuser=json.results[0];this.user=`${user.name.title}${user.name.first}${user.name.last}`;}catch(error){console.log(error)}}},...
Establecemos un watcher que detecte un cambio en la variableuser y permita actualizar el valor deoldUser.
Permiten establecer y recuperar la información modificada de una variable sin modificar su valor.
Generamos un nuevo componentecomputed-properties-get-set.js
Vue.component('computed-properties-get-set',{data(){return{amount:0}},template:` <div> <h2>Computed Properties get && set</h2> <input v-model="amount" /> <p>{{ amountFormatted }}</p> </div> `});
Establecemos como variables calculadas lo siguiente:
computed:{amountFormatted:{get(){return`${this.amount}€`;},set(newValue){this.amount=newValue;}}},
Elget establecerá el formato que se quiere recuperar y elset simplemente establecerá el valor.
Permite de forma dinámica establecer los componentes que se muestran.
Creamos una carpetadynamic-components con 3 componentes que contengan únicamente una template para ver cómo se cambia de uno a otro.
Generamos un nuevo componenteload-dynamic-component.js:
Vue.component('load-dynamic-components',{data(){return{components:['cmp1','cmp2','cmp3'],currentComponent:'cmp1'}},methods:{changeComponent(cmp){this.currentComponent=cmp;}},template:` <div> <h2>Componentes dinámicos</h2> <button v-for="cmp in components" @click="changeComponent(cmp)"> Seleccionar {{ cmp }} </button> <component :is="currentComponent" /> </div> `})
A la etiquetacomponent le pasamos la directiva :is en donde establecemos el nombre del componente que debe cargarse en cada momento. El evento que genera cada botón permitirá que se carguen los componentes de forma dinámica.
Un mixin es una forma de heredar datos para poder reutilizar información.
Generamos un nuevo componentemixiins.js que va a contener dos mixins. En este caso, se mezclan los elementos de ambos mixin, y en el caso en el que sus keys sean iguales, se sobrescriben.
letmyMixin={mounted(){console.log('MIXIN 1 init');console.log(this.mixinData);this.test()},data(){return{mixinData:'Mixin Data 1'}},methods:{test(){console.log('test from mixin');}}}letmyMixin2={mounted(){console.log('MIXIN 2 init');console.log(this.mixinData);console.log(this.mixinData2);this.test()},data(){return{mixinData:'Overwriting data',mixinData2:'Mixin Data 2'}},}Vue.component('mixins',{mixins:[myMixin,myMixin2],mounted(){console.log("Mounted from component with mixins")},template:` <div> <h2>Uso de mixins</h2> <p>{{mixinData}}</p> <p>{{mixinData2}}</p> </div> `})
La salida que se obtiene por consola tras la carga será la siguiente:
Las directivas son atributos especiales que se colocan en las etiquetas HTML y están prefijados por v- (v-for, v-bind, v-on...).
Estas directivas permiten realizar acciones dinámicas potentes (bucles, condicionales, etc...) que no se pueden realizar en HTML por si solo.
Para este ejemplo creamos una carpeta directivas y dentro un archivofocus.js.
Vue.directive('focus',{inserted(el){el.focus();}})
Ahora podemos utilizar v-focus dentro de un input para que en la carga el foco vaya a ese input.
Generamos una nueva directivachange-styles.js
Vue.directive('change-styles',(el,binding)=>{el.style.backgroundColor=binding.value.backgroundColor;el.style.color=binding.value.color;})
Ahora podemos utilizar esta directiva para cambiar estas las propiedades csscolor ycolor de fondo de un componente, bien sea de forma explícita o a través de una variable:
Vue.component('message',{data(){return{message:'Hola Mundo',style:{backgroundColor:'red',color:'white'}}},template:` <div v-change-styles="style"> <h1>Componente Message</h1> <p v-change-styles="{color: 'blue'}">{{message}}</p> </div> `});
Creamos una carpetafilters y en ella un archivoarrow-filter.js.
Vue.filter('arrow_filter',(value),params=>{return`${params}${value}`})
Este filtro permite modificar un parámetro. En este caso si el parámetro es 21 devolverá => 21.
Para aplicar el filtro se utiliza la siguiente sintáxis:
<p>{{ amountFormatted | arrow_filter(params)}}</p>
Permiten añadir funcionalidad adicional a VueJS de forma sencilla.
Creamos una nueva carpetaplugins y en su interior un archivoaboutMe.js.
constAboutMe={install:(Vue,options)=>{const{ job}=options;Vue.prototype.$me=(name,age)=>{return`Mi nombre es${name}, tengo${age} años y trabajo de${job}`}}}Vue.use(AboutMe,{job:'Programador'})
Una vez cargado el plugin, la variable $me estará disponible en la instancia de vue y será accesible desde componentes hijos utilizando$parent.
Las props son propiedades que se pasan de un componente padre a un componente hijo.
Pueden definirse mediante un array:
Vue.component('props',{props:['name','surname'],template:` <div> <h2>Props con VueJS 2</h2> <p>{{ name }} {{ surname }}</p> </div> `})
O mediante un objeto, para de esta forma definir tipos y propiedades:
Vue.component('props',{props:{name:{type:String,required:true},surname:{type:String,required:false},age:{type:Number,required:true,validator:value=>{if(value<0){console.error("La edad no puede ser menor que 0");returnfalse;}if(value<18){console.warn("Eres menor de edad...");returnfalse;}returntrue;}}},template:` <div> <h2>Props con VueJS 2</h2> <p>{{ name }} {{ surname }} Edad: {{age}}</p> </div> `})
Las Props en Vuejs nos permiten pasar datos a un componente al momento de utilizarlo:
<super-componente:nombre="variableNombreSuperComponente"/>
En este caso al componente super-componente le estamos pasando un dato de entrada llamado nombre, para utilizarlo en dicho componente haríamos lo siguiente:
<template><div> {{ nombre }}</div></template><script>exportdefault{props:['nombre']}</script>
El problema está en que si queremos que este dato sea reactivo utilizando v-model tendríamos un error:
<template><div><inputv-model="nombre"/></div></template><script>exportdefault{props:['nombre']}</script>
Esto significa que no podemos modificar una Prop de forma directa, para solucionar esto realmente existen muchos caminos, pero uno muy común que sirve en la mayoría de los casos es utilizar en lugar de un valor, un objeto:
<super-componente:objetoConNombre="objetoNombreSuperComponente"/><template><div><inputv-model="objetoConNombre.nombre"/></div></template><script>exportdefault{props:['objetoConNombre']}</script>
About
Resources
Uh oh!
There was an error while loading.Please reload this page.