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″]