Praktické príklady s Vue – 2/x
V predošlom príklade sme si tabuľku plnili AJAX-om falošnými údajmi. V tomto teda budeme modernejší a budeme si vykreslovať reálne údaje a dokonca v reálnom čase, pomocou WebSockets technológie. Konkrétne to budú kurzy krypto mien Bitcoin, Litecoin a Ethereum, prevzaté z Bitstamp.net.
A tento krát responzívne,
vrátane ukážky ďalších vlastností Vue, ako „conditional rendering“, „content distribution with slots“, „filters“, či „class bindings“ – pripájania CSS tried na základe podmienok, či výpočtov. Ešte pár vysvetliviek ku kódu:
- Ako zdroj údajov nám slúži Bitstamp public API, ktoré však nepoužíva websockets priamo, ale pomocou knižnice Pusher. Pusher je wrapper nad websockets implementujúci pub/sub pattern za účelom abstrakcie – ešte jednoduchšieho použitia websockets.
- Knižnica Numerals slúži na formátovanie čísiel. V našom prípade ceny na dve desatinné miesta, podľa slovenských pravidiel (napr. desatinná čiarka, miesto bodky).
- Komponenty sú tento krát použité dva, nie jeden. Z toho jeden je registrovaný lokálne a druhý globálne a jeden má klasickú šablónu (template), druhý zasa tzv. X-template. Len aby ste videli, že to ide viacerými spôsobmi a aby ste si všimli, že kým globálny komponent nemusím nikde spomenúť, lokálny som musel inštancii Vue vyslovene dať na vedomie.
- No a CSS som tento krát neflákol, ale ani sa s ním nehral. Aby bol príklad responzívny, použil som Bulma framework. Ten som zvolil predovšetkým preto, že je to „pure CSS“ framework, čiže bez JavaScriptu a preto, že je flex-based a tak nám idú vytvoriť rovnako vysoké panely bez ohľadu na veľkosť obsahu obsahu – niečo, čo v Bootstrap(3) nejde.
<link href="https://unpkg.com/bulma@0.5.3/css/bulma.css" rel="stylesheet">
<div id="app">
<app-layout>
<price-panel pair="btc/eur" :conn="pusher"></price-panel>
<price-panel pair="ltc/eur" :conn="pusher"></price-panel>
<price-panel pair="eth/eur" :conn="pusher"></price-panel>
</app-layout>
</div>
<script id="app-layout" type="text/x-template">
<div class="tile is-ancestor">
<div class="tile is-parent">
<slot></slot>
</div>
</div>
</script>
<template id="price-panel">
<article class="tile is-child box has-text-centered">
<p class="title">AKTUÁLNA CENA</p>
<p class="subtitle">Pre menový pár {{ pair | capitalize }}</p>
<p v-if="!price">
Čakajte prosím, kým sa neuskutoční nový obchod s touto menou.
</p>
<p v-else class="content is-size-4 has-text-weight-bold" :class="[color]">{{ price | skFormat }}</p>
</article>
</template>
<script src="https://unpkg.com/vue@2.4.4/dist/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pusher/4.1.0/pusher.min.js"></script>
<script src="https://unpkg.com/numeral@2.0.6/min/numeral.min.js"></script>
<script src="https://unpkg.com/numeral@2.0.6/min/locales/sk.min.js"></script>
<script>
var pricePanel = {
template: '#price-panel',
props: ['pair', 'conn'],
data () {
return {
subscription: null,
price: ''
}
},
computed: {
channel () {
return 'live_trades_' + this.pair.replace('/', '')
},
color () {
switch (this.pair) {
case 'btc/eur': return 'has-text-warning'
case 'ltc/eur': return 'has-text-grey-light'
case 'eth/eur': return 'has-text-primary'
default: return ''
}
}
},
filters: {
skFormat (price) {
if (!price) return ''
return numeral(price).format('0.00') + ' €'
},
capitalize (pair) {
return pair.toUpperCase()
}
},
methods: {
onTrade (trade) {
this.price = trade.price
},
subscribe () {
this.subscription = this.conn.subscribe(this.channel)
this.subscription.bind('trade', this.onTrade)
},
unsubscribe () {
this.subscription.unbind('trade', this.onTrade)
this.conn.unsubscribe(this.channel)
}
},
created() {
this.subscribe()
},
beforeDestroy(){
this.unsubscribe()
}
}
Vue.component('app-layout', {
template: '#app-layout'
})
new Vue({
el: '#app',
components: {
'price-panel': pricePanel
},
data: {
pusher: null
},
created () {
this.pusher = new Pusher('de504dc5763aeef9ff52')
numeral.locale('sk')
}
})
</script>
[iframe src=“https://jsfiddle.net/provuecateur/dnznkd77/embedded/result,html,js/“ width=“100%“ height=“560″]