Una expresión representa el valor de las propiedades de data, se puede usar código js, sumar números, expresiones boolenas, funciones.
<h1>{{ title }}</h1>
<p>{{ 1 + 1 + 1 }}</p>
<p>{{ true || false }}</p>
<p>{{ true ? true : false }}</p>
<p>{{ 'string'.toUpperCase() }}</p>
<p>{{ JSON.stringify({ name: 'nacho'}) }}</p>
var app = new Vue({
el: '#app',
data: {
title: 'Hola Vue! 2020'
}
})
Si deseo inspeccionar en consola usar:
app.title
Permite que los atributos html tengan valores dinámicos: href, title, alt, src.
Directivas permite manipular el dom de forma declarativa: v-bind y v-bind , son directiva especial que se aplica en atributos html, para ello se pone ':'
<img v-bind:src="img" v-bind:alt="name">
var app = new Vue({
el: '#app',
data: {
name: 'Bitcoin',
img: 'https://cryptologos.cc/logos/bitcoin-btc-logo.png'
}
})
Permite renderizar contenido de forma condicional.
<span v-if="changePercent > 0"> 👍 </span>
<span v-else-if="changePercent < 0"> 👎</span>
<span v-else> 🤞 </span>
<span v-show="changePercent > 0"> 👍 </span>
<span v-show="changePercent < 0"> 👎</span>
<span v-show="changePercent === 0"> 🤞</span>
var app = new Vue({
el: '#app',
data: {
changePercent:10
}
})
v-if, si no cumple la condicion, remueve el elemento del DOM, Si es algo fijo y no cambiara a lo largo del tiempo usar v-if
v-show, si no cumple condicion renderiza en display:none Si el elemento cambia constantemente usar v-show
Directiva v-for: permite interactuar con listas de arreglos.
La propiedad key permite identificar a cada elemento, si la lista se reordene o tenga actualizaciones, se ordene.
Podemos usar los ìndices (p, i), donde p son los valores e i, el indice
En un v-for se puede usar con array y array de objetos
<ul>
<li v-for="(p, i) in prices" v-bind:key="p">
{{ i }} - {{ p }}
</li>
</ul>
<ul>
<li v-for="(p, i) in priceWithDays" v-bind:key="day">
{{ i }} - {{ p.day }} - {{ p.value }}
</li>
</ul>
var app = new Vue({
el: '#app',
data: {
prices: [8400,7900,8200,9000,9400,1000,2000],
}
})
Eventos: click, mouseover
Methods: Objeto de la instancia de vue donde se puede deifnir funciones, que se pueden utilizar en diferetnes contextos, principalmente para atacharse a eventos que puede ser disparados por la vista.
v-on: directiva que sirve para escuchar eventos del DOM, tales como onclick, onmouseover, mouseout, para ejecutar alguna función.
<span v-on:click="toggleShowPrices"> ver precios {{ showPrices ? '🙉' : '🙈'}} </span>
var app = new Vue({
el: '#app',
data: {
showPrices: false
},
methods: {
toggleShowPrices(){
this.showPrices = !this.showPrices
}
}
})
Con la directiva v-bind, se puede cambiar clases en tiempor real, segùn condicion. Se puede aplicar el atributo class con v-bind a travez de objetos
v-bind usabamos para modificar los atributos de html, link, src, alt, pero en caso de las clases podemos usar una ternari, un string u objeto
<h1 v-bind:class="changePercent > 0 ? 'green' : 'red' ">{{ name }}
</h1>
var app = new Vue({
el: '#app',
data: {
name: 'Bitcoin',
changePercent:10
}
})
<ul v-show=showPrices>
<li class="uppercase"
v-bind:class="{ orange: p.value == price, red: p.value < price, green: p.value > price }"
v-for="(p, i) in priceWithDays"
v-bind:key="p.day">
{{ i }} - {{ p.day }} - {{ p.value }}
</li>
</ul>
var app = new Vue({
el: '#app',
data: {
name: 'Bitcoin',
changePercent:10,
price: 8400,
}
})
De igual forma que usamos v-bind con class, se puede aplicar estilos en el html.
<div id="app" v-bind:style="{ background: '#' + color }">
<img v-bind:src="img" v-bind:alt="name" width="100">
<h1 v-bind:class="changePercent > 0 ? 'green' : 'red' ">{{ name }}
<span v-on:click="toggleShowPrices"> {{ showPrices ? '🙉' : '🙈'}} </span>
</h1>
</div>
var app = new Vue({
el: '#app',
data: {
name: 'Bitcoin',
color: 'f4f4f4'
},
methods: {
toggleShowPrices(){
this.showPrices = !this.showPrices
this.color = this.color.split('').reverse().join('')
}
}
})
Para interactuar con los valores en data, utilizamos this.nombre de variable
Las Propiedades computadas son aquillas pro que se generean a partir de otras propiedades, permite generar un valor nuevo.
La ueva propiedad se modifica, cada vez que se cambia una propiedad de las asignadas.
Propiedades que se calculan en tiempo real en base a los valores de otras propiedades
<div id="app">
<img v-bind:src="img" v-bind:alt="name" width="100">
<h1 > {{ title }} </h1>
<h2 > {{ reversedMessage }} </h2>
<span v-on:click="toggleShowPrices"> {{ showPrices ? '🙉' : '🙈'}} </span>
</div>
var app = new Vue({
el: '#app',
data: {
name: 'Bitcoin',
symbol: 'BTC',
img: 'https://cryptologos.cc/logos/bitcoin-btc-logo.png',
changePercent: 2,
color: 'f4f4f4',
showPrices: false
},
computed: {
title () {
return `${this.name} - ${this.symbol}`
},
reversedMessage: function () {
return this.name.split('').reverse().join('')
}
},
watch: {
showPrices (newVal, oldVal) {
console.log(newVal, oldVal);
}
},
methods: {
toggleShowPrices(){
this.showPrices = !this.showPrices
this.color = this.color.split('').reverse().join('')
}
}
})
La propiedad title() se cambiara, cada vez que se cambie alguna propiedad de name o symbol De igual forma como method, this es la manera que utilizamos para acceder a las propiedades de la instancia de vue.
Una propiedad computada, se utiliza como una propiedad normal {{ title }}
Los watchers, tienen comportamiento similar, en vez de ser funciones que devuelven un valor, son funciones que ejecutan un codigo.
El nombre de la funcion watcher debe ser el mismo de la propiedad data. El watcher recibe 2 valores, valor nuevo y valor viejo
Directiva v-model, permite linkear lo que escribe un usario a travez de las prpiedades de data.
<div id="app">
<input type="number" v-model="value">
<span> {{ value }}</span>
<span> {{ converteValue }}</span>
</div>
var app = new Vue({
el: '#app',
data: {
name: 'Bitcoin',
symbol: 'BTC',
img: 'https://cryptologos.cc/logos/bitcoin-btc-logo.png',
changePercent: 2,
value: 0,
color: 'f4f4f4',
price: 8400,
showPrices: false
},
computed: {
title () {
return `${this.name} - ${this.symbol}`
},
converteValue () {
if(!this.value){
return 0
}
return this.value / this.price
},
},
watch: {
showPrices (newVal, oldVal) {
console.log(newVal, oldVal);
}
},
methods: {
toggleShowPrices(){
this.showPrices = !this.showPrices
this.color = this.color.split('').reverse().join('')
}
}
})
Directiva v-model, permite linkear las cosas que puede escribir el usuario en un input con las propiedades definidas en data (two day databinding)
``` html
<div id="app">
<input type="number" v-model="value"> <br>
<span> data simple: {{ value }}</span> <br>
<span> data doble {{ converteValue }}</span>
</div>
var app = new Vue({
el: '#app',
data: {
name: 'Bitcoin',
value: 0,
price:2
},
computed: {
converteValue() {
if(!this.value) {
return 0
}
return this.value * this.price
}
}
})
La funcion Vue component permite registrar y crear componentes nuevos, se puede disponer de data, method, computer, etc, en vue componente se crea los template dentro de un string literal-
Cuando se crea un vue.component, permite crear el tag con el mimo nombre, o tambien podemos usar la sinxataxis minuscula y con guiones.
El componente padre enviar informacion al componente hijo para que lo utilice
<div id="app">
<coin-detail
v-bind:img="img"
v-bind:name="name"
v-bind:price="price"
v-bind:title="title"
v-bind:changePercent='changePercent' ></coin-detail>
</div>
Vue.component('CoinDetail', {
props: ['title','changePercent','img','name','price','priceWithDays'],
data () {
return {
showPrices: false,
value: 0,
}
},
methods: {
toggleShowPrices() {
this.showPrices = !this.showPrices
}
},
computed: {
converteValue () {
if(!this.value){ //checkea si el precio tiene un valor, sino retorna 0
return 0
}
return this.value * this.price
}
},
template: `
<div>
<img
v-on:mouseover="toggleShowPrices"
v-on:mouseout="toggleShowPrices"
v-bind:src="img" v-bind:alt="name" width="100"
>
<h1 v-bind:class="changePercent > 0 ? 'green' : 'red' ">{{ title }}
<span v-if="changePercent > 0"> 👍</span>
<span v-else-if="changePercent < 0"> 👎</span>
<span v-else> 🤞 </span>
<span v-on:click="toggleShowPrices"> {{ showPrices ? '🙉' : '🙈'}} </span>
</h1>
<input type="number" v-model="value">
<span> {{ converteValue }}</span>
<ul>
<li v-for="(p, i) in priceWithDays" v-bind:key="day">
{{ i }} - {{ p.day }} - {{ p.value }}
</li>
</ul>
{{ priceWithDays }}
</div>
`,
})
new Vue ({
el: '#app',
data () {
return {
title: 'Vue Components ',
name: 'Bitcoin ',
symbol: 'BTC',
img: 'https://cryptologos.cc/logos/bitcoin-btc-logo.png',
changePercent: -10,
value: 0,
color: 'f4f4f4',
price: 5,
priceWithDays: [
{ day: 'lunes', value: 8400 },
{ day: 'martes', value: 8100 },
{ day: 'miercoles', value: 8300 },
{ day: 'jueves', value: 8210 },
{ day: 'viernes', value: 7400 },
{ day: 'sábado', value: 9400 },
{ day: 'domingo', value: 9400 },
],
}
},
})
La comunicacion de padre hace hijos es atravez de propiedades props: se define las propiedades donde el componente padre setee al componente hijo el componente hijo, no puede modificar la propiedad padre
<div id="app">
<h1>{{ title }}</h1>
<counter></counter>
</div>
Vue.component('counter', {
data () {
return {
counter: 0
}
},
methods: {
increment(){
this.counter += 1
}
},
template: `
<div>
<button v-on:click="increment"> Click me! </button>
<span> {{ counter }} </span>
</div>
`,
})
new Vue ({
el: '#app',
data () {
return {
title: 'Hola Vue!',
}
},
})
La comunicacion de hijo a padres es atravez de eventos. v:bind modificar en tiempo real, atributo dinamico v-on evento para que el hijo envia data al padre
Permite que el contenido padre puede usar compoentes del hijo
En el componente hijo se define:
<slot name="texto"></slot>
<slot name="enlace"></slot>
en el padre se define:
<template v-slot:texto>
<p>Esto es un texto ipsum dolor sit amet consectetur adipisicing elit. Officiis dicta soluta perspiciatis ab ut, nihil harum molestiae, commodi maxime explicabo inventore placeat possimus repudiandae voluptatem cum numquam necessitatibus excepturi quibusdam!</p>
</template>
<template v-slot:enlace>
<a href="#">Es un Link</a>
</template>
tag template: renderiza contenido sin necesidad de incluir un tag, cuando se usa template se usa direvitva v-slot:text
** Se puede distribuir contenido desde un componente padre a un componente hijo
Para terminar con el sistema de compoenentes se tiene que ver el ciclo de vida de estos componentes Hooks son diferentes eventos que podemos representar en nuestro componente a travez de funciones
created () {
console.log( 'created ...')
},
mounted() {
console.log( 'mounted ...')
},
created se recomienda para poder obtener informacion atravez de un api Rest Mounted, tengo disponible el DOM, puedo acceder al domn, elemento html que no tengo en el created
Vue component: crear contenido html y lo agrupa El Componente padre puede enviar data al hijo con propiedades El hijo envia al padre mediante eventos slot, ipermite amppliear la distribución de contenido
Práctica:
Identificar: node --version : v10.15.2 npm --version: 6.13.4
https://github.com/vuejs/vetur https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint https://prettier.io/ https://github.com/vuejs/vue-devtools
Instalar CLI: npm install -g @vue/cli //Instala de forma global, @ significa que pertenece a la organizacion vue --version vue create platzi-exchange | vue create --help
//Instala de forma global, @ significa que pertenece a la organizacion
npm install -g @vue/cli
vue --version
vue create --help
//Creacion de proyecto
vue create platzi-exchange
Option: manual
- babel
- Linter / formater
- ESLINTs Pretier
- Lint to save
cd platzi-exchange
$ npm run serve
- src main.js: muestra import Vue from 'vue' (node modules)
- App.vue se estructura el html/template, el scrip y styles, en script elexport default es parte de los modulos de ecmascript
Formas de ejecutar vue-cli:
npm run lint //permite formatear codigo
npm run build //ambiente producción, genera carpeta dist
npm i -g serve //permite generar un servidor local
serve -s dist //correr servidor web local de la carpeta list
vue ui // genera app local amigable para gestionar proyectos
Permite agregar plugin al proyecto: vue add
vue add @ianaya89/tailwind
en main.js, importamos css
import '@/assets/css/tailwind.css'
Se agregará un componente Header
- Se crea en src/componentes/PxHeader.vue e importa en app.vue, luego se escribe el tag html con el nombre del componente
<PxHeader />
import PxHeader from '@/components/PxHeader.vue'
export default {
name: 'App',
components: {
PxHeader
}
}
Se puede poner componentes dentro de otros componentes
1.- se instala en dependencies
npm i -S vue-router
2.- se crea routers.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/views/Home'
Vue.use(Router)
export default new Router({
mode: 'history', l
routes: [
{
path: '/',
name: 'home',
component: Home
}
]
})
3.- se crea componente Home:
<template>
<div>
<px-assets-table />
</div>
</template>
<script>
export default {
name: 'Home',
}
</script>
4.- en app.vue la etiqueta router-view es la que realiza la funcionalidad de router en componentes
<template>
<div id="app">
<router-view class="container" />
</div>
</template>
5.- en main.js, se importa router.vue
import router from '@/router' //añadir
new Vue({
router, //añadir
render: h => h(App)
}).$mount('#app')
Adicional, router, nos permite linkear para saber a donde tiene que llevar
<router-link to="/">Volver a la pagina de Inicio</router-link>
Crearmo api.js, consumimos servicios de:
https://docs.coincap.io/?version=latest#ee0c0be6-513f-4466-bbb0-2016add462e9
const url = 'https://api.coincap.io/v2'
function getAssets() {
return fetch(`${url}/assets?limit=20`)
.then(res => res.json())
.then(res => res.data)
}
export default {
getAssets,
}
En home.vue, importamos api, asignamos getAssets en la función created para obtener data
<template>
<div>
<px-assets-table :obtenerData="obtenerData" />
</div>
</template>
<script>
import api from '@/api'
import PxAssetsTable from '@/components/PxAssetsTable.vue'
export default {
name: 'Home',
components: {
PxAssetsTable
},
data() {
return {
obtenerData: []
}
},
created() {
api
.getAssets()
.then(datos => (this.obtenerData = datos))
}
}
</script>
En Componente de tabla, se agrega propiedades para consumir data
<tbody>
<tr
v-for="a in obtenerData"
:key="a.id"
>
<td>
<b>#{{ a.rank }}</b>
</td>
<script>
export default {
name: 'PxAssetsTable',
props: {
obtenerData: {
type: Array,
default: () => []
}
}
}
</script>
plugin numeral permite formatear números
npm i -S numeral
Creamos filters.js
import numeral from 'numeral'
const dollarFilter = function(value) {
if (!value) {
return '$ 0'
}
return numeral(value).format('($ 0.00a)')
}
En main.js, importamos el archivo filters
import { dollarFilter, percentFilter } from '@/filters'
Vue.filter('dollar', dollarFilter)
Vue.filter('percent', percentFilter)
En componente table (PxAssetssTable.vue)
<td>
<b>{{ a.changePercent24Hr | percent }}</b>
</td>
aplicar classes dinámicas con v-bind:class="a.changePercent24Hr" include ('-') true false
<td :class="
a.changePercent24Hr.includes('-')
? 'text-red-600'
: 'text-green-600'
"
>
{{ a.changePercent24Hr | percent }}
</td>
Indicamos con router-link linkear de forma dinamicas las páginas según parametros.
<td>
<router-link
:to="{ name: 'coin-detail', params: { id: a.id } }"
>{{ a.name }}</router-link
>
</td>
De forma programatica Crear componente PxButton.vue
<template>
<button
@click="buttonClick"
>
<p>
<slot></slot>
</p>
</button>
</template>
<script>
export default {
name: 'PxButton',
props: {
isLoading: {
type: Boolean,
default: false
}
},
methods: {
buttonClick() {
this.$emit('custom-click')
}
}
}
</script>
En componente table
<td class="hidden sm:block">
<px-button @custom-click="goToCoin(a.id)">
<span>Detalle</span>
</px-button>
</td>
<script>
import PxButton from '@/components/PxButton'
export default {
name: 'PxAssetsTable',
components: { PxButton },
methods: {
goToCoin(id) {
this.$router.push({ name: 'coin-detail', params: { id } })
}
}
}
</script>
Se utilizará vue-spinners para loader de espera y vuechart para gráfico
npm i -S @saeris/vue-spinners vue-chartkick
npm i -S chart.js
En main.js, importamos los componentes de terceros, usamos Vue.use
import Chart from 'chart.js'
import Chartick from 'vue-chartkick'
import { VueSpinners } from '@saeris/vue-spinners'
Vue.use(VueSpinners)
Vue.use(Chartick.use(Chart))
En Home.vue
<bounce-loader :loading="isLoading" :color="'#68d391'" :size="100" />
function getMarkets(coin) {
return fetch(`${url}/assets/${coin}/markets?limit=5`)
.then(res => res.json())
.then(res => res.data)
}
function getExchange(id) {
return fetch(`${url}/exchanges/${id}`)
.then(res => res.json())
.then(res => res.data)
}
$set, solo en objetos y arrays, para agregar objetos cuaando no estan desde el pricipio recibe 1er argumento el objeto al que queremos agregar la propiedad
this.$set(exchange, 'url', res.exchangeUrl)
Para filtrar data, realizamos una propiedad computada indicamos si symbol o name incluye el texto filter v:bind
Para mostrar de mayor a menor, usamos la funcion sort. como parametros, filtro actual y el modificado.
<input
id="filter"
placeholder="Buscar..."
type="text"
v-model="filter"
/>
computed: {
filteredAssets(){
const altOrder = this.sortOrder === 1 ? -1 : 1
return this.obtenerData
.filter(
a =>
a.symbol.toLowerCase().includes(this.filter.toLowerCase()) ||
a.name.toLowerCase().includes(this.filter.toLowerCase())
)
.sort((a, b) => {
if (parseInt(a.rank) > parseInt(b.rank)) {
return this.sortOrder // 1
}
return altOrder
})
}
},
cambiamos el array por la propiedad computada
<tr
v-for="a in filteredAssets"
:key="a.id"
>
<td>
En PxHeader.vue agregaremos links para ir a las secciones
<router-link
v-for="l in links"
:key="l.title"
:to="l.to"
>{{ l.title }}</router-link>
Seteamos los links
data() {
return {
links: [
{
title: 'BTC',
to: { name: 'coin-detail', params: { id: 'bitcoin' } }
},
{
title: 'ETH',
to: { name: 'coin-detail', params: { id: 'ethereum' } }
},
{
title: 'XRP',
to: { name: 'coin-detail', params: { id: 'ripple' } }
}
]
}
}
En coindetail: Agregamos whatcher para que en el detalle, se pueda usar los links
watch: {
$route() {
this.getCoin()
}
},