Vue.JS

Componentes
David Daza
Full Stack Developer - Datasketch

@ddazal
@_daviddaza

Lugar · Bebidas · Comida
Agradecimientos
Recursos
Antes de empezar
Las interfaces de usuario pueden ser divididas en componentes
Barra de navegación
Footer
Carousel
Card
Card
Card
Card
Card
Sidebar
Las interfaces de usuario pueden ser abstraídas en un árbol de componentes

Bloques independientes y reutilizables de una interfaz
Vue.component
Vue.component('welcome', {
template: '<h1>Welcome</h1>'
})
new Vue({
el: '#app'
})Vue.component
<div id="app">
<welcome></welcome>
<!-- <welcome /> -->
<!-- <Welcome></Welcome> -->
<!-- <Welcome /> -->
</div>Vue.component
components
const Welcome = {
template: '<h1>Welcome</h1>'
}
new Vue({
el: '#app',
components: { Welcome }
})components
<div id="app">
<Welcome />
</div>components
¿Cómo le pasamos datos a los componentes?
props
Vue.component('welcome', {
props: ['name'],
template: '<h1>Welcome, {{ name }}</h1>'
})
new Vue({
el: '#app',
data() {
return {
name: 'babies'
}
}
})props
<div id="app">
<Welcome :name="name" />
</div>props
props validation
Vue.component('welcome', {
props: {
name: {
type: String,
default: 'stranger',
// required: true
// validator(val) { return val.length > 1}
}
},
template: '<h1>Welcome, {{ name }}</h1>'
})
new Vue({
el: '#app',
data() {
return {
name: 'babies'
}
}
})props validation
Ejemplo
Ejemplo
Resumen
✅ Los componentes son bloques independientes y reutilizables de una interfaz
✅ Los componentes reciben datos mediante la propiedad props
✅ data debe ser una función
✅ Un solo elemento raíz por componente
Flujo de datos
Padre
Hijo
pasa props
emite eventos
¿Cómo emitimos eventos?
$emit
const Counter = {
props: {
count: Number
},
template: `<button @click="increment">{{ count }}</button>`,
methods: {
increment() {
this.$emit('increment')
}
}
}
new Vue({
el: '#app',
components: { Counter },
data() {
return {
count: 0
}
},
methods: {
incrementCount() {
this.count += 1
}
}
})$emit
<div id="app">
<Counter :count="count" @increment="incrementCount"/>
</div>$emit
$emit - parámetros
const Counter = {
props: {
count: Number
},
template: `<button @click="increment">{{ count }}</button>`,
methods: {
increment() {
this.$emit('increment', 2)
}
}
}
new Vue({
el: '#app',
components: { Counter },
data() {
return {
count: 0
}
},
methods: {
incrementCount(factor) {
this.count += factor
}
}
})$emit - parámetros
$emit - Event
Vue.component('MouseTracker', {
props: {
pos: Object,
},
template: `
<div class="mouse-tracker" @mousemove="$emit('track', $event)">
</div>
`
})
new Vue({
el: '#app',
data() {
return {
pos: { x: 0, y: 0 },
}
},
methods: {
updatePosition(event) {
this.pos.x = event.clientX
this.pos.y = event.clientY
}
}
})$emit - Event
Resumen
✅ Los hijos pueden emitir eventos a sus padres utilizando el método $emit
✅ Los props no deben ser modificados por el componente que los recibe, sino por el componente padre
✅ Para acceder al objeto Event, emite el evento con la variable $event
v-model
<input v-model="text" />
<input :value="text" @input="text = $event.target.value" />
v-model
✅ Enlazar el atributo value a un prop value
✅ Emitir el evento input con el nuevo valor
v-model
Vue.component('my-search', {
props: ['value'],
template: `
<div class="my-search">
<input type="text" placeholder="Search" :value="value" @input="$emit('input', $event.target.value)"/>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M12.9 14.32a8 8 0 1 1 1.41-1.41l5.35 5.33-1.42 1.42-5.33-5.34zM8 14A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></svg>
</div>
`
})
new Vue({
el: '#app',
data() {
return {
search: ''
}
}
})v-model
<div id="app">
<my-search v-model="search"></my-search>
</div>v-model
Ciclo de vida
✅ beforeCreate
✅ created
✅ beforeMount
✅ mounted
✅ beforeUpdate
✅ updated
✅ beforeDestroy
✅ destroyed
beforeCreate
Es llamado antes de que la instancia pueda observar los datos y configurar eventos
created
La instancia configura los datos, computed properties, métodos, watch/event callbacks.
beforeMount
$el está disponible
mounted
Se hace render del DOM
beforeUpdate
Es llamado cuando cambian los datos, pero antes de actualizar el DOM
updated
Es llamado cuando el DOM se ha actualizado con el cambio de los datos
beforeDestroy
Es llamado justo antes de destruir la instancia/componente
destroyed
El componente ha sido eliminado totalmente
Break
🧘🏽♀️🧘🏾♂️
Slots
Slots
<div class="notification">
<div class="notification-body">
<p>Account verified</p>
<div class="notification-dismiss">
<button>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zM11.4 10l2.83-2.83-1.41-1.41L10 8.59 7.17 5.76 5.76 7.17 8.59 10l-2.83 2.83 1.41 1.41L10 11.41l2.83 2.83 1.41-1.41L11.41 10z"/></svg>
</button>
</div>
</div>
</div>Slots
<div class="notification">
<div class="notification-body">
<slot></slot>
<div class="notification-dismiss">
<button>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zM11.4 10l2.83-2.83-1.41-1.41L10 8.59 7.17 5.76 5.76 7.17 8.59 10l-2.83 2.83 1.41 1.41L10 11.41l2.83 2.83 1.41-1.41L11.41 10z"/></svg>
</button>
</div>
</div>
</div>Slots
Vue.component('notification', {
template: `
<div class="notification">
<div class="notification-body">
<slot></slot>
<div class="notification-dismiss">
<button>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zM11.4 10l2.83-2.83-1.41-1.41L10 8.59 7.17 5.76 5.76 7.17 8.59 10l-2.83 2.83 1.41 1.41L10 11.41l2.83 2.83 1.41-1.41L11.41 10z"/></svg>
</button>
</div>
</div>
</div>
`
})
new Vue({
el: '#app'
})Slots
<div id="app">
<notification>
<p>Account verified!</p>
</notification>
</div>Slots
Named slots
Named slots
<div class="modal">
<div class="modal-header">
<button>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zM11.4 10l2.83-2.83-1.41-1.41L10 8.59 7.17 5.76 5.76 7.17 8.59 10l-2.83 2.83 1.41 1.41L10 11.41l2.83 2.83 1.41-1.41L11.41 10z"/></svg>
</button>
</div>
<div class="modal-body">
<h3 class="modal-title">Payment successful!</h3>
<p class="modal-content">Thank you for shopping with us! We are lucky to have customers like you so your order will be as soon as possible in your door ❤️</p>
</div>
<div class="modal-footer">
<button>Done</button>
</div>
</div>Named slots
<div class="modal">
<div class="modal-header">
<button>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zM11.4 10l2.83-2.83-1.41-1.41L10 8.59 7.17 5.76 5.76 7.17 8.59 10l-2.83 2.83 1.41 1.41L10 11.41l2.83 2.83 1.41-1.41L11.41 10z"/></svg>
</button>
</div>
<div class="modal-body">
<h3 class="modal-title"><slot name="title"></slot></h3>
<p class="modal-content"><slot name="content"></slot></p>
</div>
<div class="modal-footer">
<button><slot name="cta"></slot></button>
</div>
</div>Named slots
Vue.component('my-modal', {
template: `
<div class="modal">
<div class="modal-header">
<button>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zM11.4 10l2.83-2.83-1.41-1.41L10 8.59 7.17 5.76 5.76 7.17 8.59 10l-2.83 2.83 1.41 1.41L10 11.41l2.83 2.83 1.41-1.41L11.41 10z"/></svg>
</button>
</div>
<div class="modal-body">
<h3 class="modal-title"><slot name="title"></slot></h3>
<p class="modal-content"><slot name="content"></slot></p>
</div>
<div class="modal-footer">
<button><slot name="cta"></slot></button>
</div>
</div>
`
})
new Vue({
el: '#app'
})Named slots
<div id="app">
<my-modal>
<template v-slot:title>
Payment successful!
</template>
<template v-slot:content>
Thank you for shopping with us! We are lucky to have customers like you so your order will be as soon as possible in your door ❤️
</template>
<template v-slot:cta>
Done
</template>
</my-modal>
</div>Named slots
<div id="app">
<my-modal>
<template #title>
Payment successful!
</template>
<template #content>
Thank you for shopping with us! We are lucky to have customers like you so your order will be as soon as possible in your door ❤️
</template>
<template #cta>
Done
</template>
</my-modal>
</div>Named slots
Named slots ⚠️
<div id="app">
<my-modal>
<template slot="title">
Payment successful!
</template>
<template slot="content">
Thank you for shopping with us! We are lucky to have customers like you so your order will be as soon as possible in your door ❤️
</template>
<template slot="cta">
Done
</template>
</my-modal>
</div>Scoped slots
Scoped slots
Vue.component('user-card', {
template: `
<div>
<slot>{{ user.firstname }} {{ user.lastname }} is {{ user.status }}</slot>
</div>`,
data() {
return {
user: {
firstname: 'Jane',
lastname: 'Doe',
status: 'connected'
}
}
}
})
new Vue({
el: '#app'
})Scoped slots
<div id="app">
<user-card></user-card>
</div>Scoped slots
Scoped slots
<div id="app">
<user-card>
Yes! {{ user.firstname }} is {{ user.status }}
</user-card>
</div>Scoped slots

Scoped slots
Vue.component('user-card', {
template: `
<div>
<slot v-bind:user="user">{{ user.firstname }} {{ user.lastname }} is {{ user.status }}</slot>
</div>`,
data() {
return {
user: {
firstname: 'Jane',
lastname: 'Doe',
status: 'connected'
}
}
}
})
new Vue({
el: '#app'
})Scoped slots
<div id="app">
<user-card v-slot="slotProps">
Yes! {{ slotProps.user.firstname }} is {{ slotProps.user.status }}
</user-card>
</div>Scoped slots
<div id="app">
<user-card v-slot="{ user }">
Yes! {{ user.firstname }} is {{ user.status }}
</user-card>
</div>Scoped slots
Ejemplo
Componentes dinámicos
<component>
Vue.component('tab-home', {
template: '<div>Home component</div>'
});
Vue.component('tab-posts', {
template: '<div>Posts component</div>'
});
Vue.component('tab-archive', {
template: '<div>Archive component</div>'
});
new Vue({
el: '#app',
data: {
currentTab: 'Home',
tabs: ['Home', 'Posts', 'Archive']
},
computed: {
currentTabComponent: function() {
return 'tab-' + this.currentTab.toLowerCase();
}
}
});<component>
<div id="app">
<button v-for="tab in tabs" :class="['tab-button', { active: currentTab === tab }]" @click="currentTab = tab">
{{ tab }}
</button>
<component v-bind:is="currentTabComponent" class="tab"></component>
</div><component>
Ejemplo
¡GRACIAS!

@ddazal
@_daviddaza
Vue.js Components
By David Daza
Vue.js Components
Slides para Meetup de Vue.JS en Bogotá. Febrero 10, 2020.
- 529