Vue.js
núria soriano
Por qué Vue?
Rápido
Vue + vue-router + vuex 26kb min+gzip
Se adapta a ti
Templates vs Render Functions vs JSX
Javascript vs Typescript
No opinionado
Escalable
Core: Declarative rendering & component system
Routing: vue-router
Large Scale State Management: vuex
Build system: vue-loader/vueify, vue-cli
SSR: vue-server-renderer
Fácil
<div id="app">
<h1>{{ message }}</h1>
</div>
<script>
var vm = new Vue({
data: {
message: 'Hello World!'
}
}).$mount('#app')
<script>
Iniciar nuestro proyecto con Vue
y Webpack
Vue CLI
npm install -g vue-cli
vue init <template-name> <project-name>
Templates
Estructura del proyecto
├─ build/ # Configuración de webpack
├─ config/ # Configuración general, variables de entorno…
├─ src/
│ ├─ main.js # Archivo principal de entrada
│ ├─ App.vue # Componente raíz
│ ├─ components/ # Componentes
│ └─ assets/ # Assets procesados por webpack (sass…)
├─ static/ # Assets estáticos no procesados por Webpack
├─ .babelrc # babel config
├─ .postcssrc.js # postcss config
├─ .eslintrc.js # eslint config
├─ .editorconfig # editor config
├─ index.html # Plantilla html
└─ package.json # Scripts y dependencias
Anatomía de un componente
Vue Single File Component
Plantilla, lógica y estilo
Usando HTML + Javascript + CSS
O Pug, CoffeeScript, SASS…
Se importa como un módulo ES2015
Hot-reload, scoped CSS…
<template>
<my-component></my-component>
</template>
<script>
import 'myComponent' from './MyComponent'
export default {
name: 'app',
components: {
myComponent
}
}
</script>
<style lang="scss" scoped>
div {
color: blue
}
</style>
Propiedades
data() {
return {
collection: [1, 2, 3, 4]
}
}
Métodos
methods: {
addNumbers() {
var moreNumbers = [5,6,7,8]
this.collection.push(...moreNumbers)
}
}
Propiedades computadas
Reactivas
computed: {
evenNumbers() {
return this.collection.filter(number => number %2 === 0)
}
}
Solo se recalculan cuando es necesario
Lifecycle hooks
Ejecutar lógica en determinados momentos
created() {
http.get('http://jsonplaceholder.typicode.com/posts')
.then(response => {
this.posts = response.data
})
.catch(e => {
this.errors.push(e)
})
}
Comunicación
entre componentes
Parent to Child
Child
export default {
props: [ 'propName' ],
// ...
}
Parent
<child-component :propName="someData">
</child-component>
export default {
props: {
propName: {
type: Boolean,
default: true
},
otherProp: {
type: String,
required: true
}
},
// ...
}
Child to Parent
Child
this.$emit('eventName', data)
Parent
<child-component @eventName="method">
</child-component>
Sync
Child
this.$emit('update:foo', newValue)
Parent
<child-component :foo.sync="bar">
</child-component>
Desde Vue 2.3
<child-component :foo="bar" @update:foo="val => bar = val">
</child-component>
Escalando
nuestra app:
Routing
Router
import User from 'src/components/User';
const router = new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
})
<div id="app">
<router-view></router-view>
</div>
Router
<router-link to="home"></router-link>
<router-link :to="{
name: 'Detail',
params: {
id: 1
}
}">
</router-link>
this.$router.push({
name: 'Detail',
params: {
id: 1
}
})
Escalando
nuestra app:
State management
State Management
Vuex
Varios componentes son dependientes del mismo estado
Sincronizar estado sin necesidad de eventos
Solución escalable para aplicaciones complejas
Fácil de debuggar
El estado
const store = new Vuex.Store({
state: {
movies: [
{ id: 1, title: '...', saved: true },
{ id: 2, title: '...', saved: false }
]
}
})
const store = new Vuex.Store({
state: {
movies: [
{ id: 1, title: '...', saved: true },
{ id: 2, title: '...', saved: false }
]
},
getters: {
savedMovies: state => {
return state.movies.filter(movie => movie.saved)
}
}
})
Objeto
No mutable directamente
Usar el estado en nuestros componentes
computed: {
movies () {
return this.$store.state.movies
},
savedMovies () {
return this.$store.getters.savedMovies
}
}
import { mapState, mapGetters } from 'vuex'
export default {
computed: {
...mapState({
'movies'
}),
...mapGetters([
'savedMovies'
])
}
}
Definir mutaciones
const store = new Vuex.Store({
state: {
movies: []
},
mutations: {
addMovie (state, movie) {
state.movies.push(movie)
}
}
})
Mutaciones asíncronas: Acciones
const store = new Vuex.Store({
state: { ... },
mutations: { ... },
actions: {
getMovies ({ commit }) {
api.getMovies()
.then( data => {
data.forEach(movie => commit('addMovie', movie))
})
}
}
})
Usar mutaciones y acciones en componentes
methods: {
addMovie (movie) {
return this.$store.commit('addMovie')
},
getMovies () {
return this.$store.dispatch('getMovies')
}
}
import { mapMutations, mapActions } from 'vuex'
export default {
methods: {
...mapMutations({
'addMovie'
}),
...mapActions([
'getMovies'
])
}
}
Bonus
Bonus
Localización: vue-i18n
Validación: vuelidate
Y más: vue-awesome
Gracias!
nuria-fl
soriano.nuria@gmail.com
pincfloit
Introducción a Vue.js
By nuria-fl
Introducción a Vue.js
- 1,559