Utilizzo di Vue.js per creare un dashboard meteo interattivo con le API
Utilizzo di Vue.js per creare un dashboard meteo interattivo con le API
Pubblicato: 2022-03-10
Riepilogo rapido ↬ La creazione di una dashboard con i dati API è spesso una faccenda complessa. Scegliere il tuo stack tecnologico, integrare le API, selezionare i grafici giusti e abbellire con gli stili CSS può diventare complicato. Questo tutorial è una guida passo passo su come creare un dashboard meteo in Vue.js utilizzando i dati API.
(Questo è un articolo sponsorizzato.) In questo tutorial creerai da zero una semplice dashboard meteo. Sarà un'applicazione client-end che non è né un esempio "Hello World", né troppo intimidatoria per dimensioni e complessità.
L'intero progetto sarà sviluppato utilizzando gli strumenti dell'ecosistema Node.js + npm. In particolare, faremo molto affidamento sull'API Dark Sky per i dati, Vue.js per tutto il lavoro pesante e FusionCharts per la visualizzazione dei dati.
Prerequisiti
Ci aspettiamo che tu abbia familiarità con quanto segue:
HTML5 e CSS3 (sfrutteremo anche le funzionalità di base fornite da Bootstrap;
JavaScript (in particolare il modo ES6 di usare il linguaggio);
Node.js e npm (le basi dell'ambiente e della gestione dei pacchetti vanno bene).
Oltre a quelli sopra menzionati, sarebbe fantastico se hai familiarità con Vue.js o qualsiasi altro framework JavaScript simile. Non ci aspettiamo che tu conosca FusionCharts : è così facile da usare che lo imparerai al volo!
Apprendimenti attesi
I tuoi insegnamenti chiave da questo progetto saranno:
Come pianificare l'implementazione di una buona dashboard
Come sviluppare applicazioni con Vue.js
Come creare applicazioni basate sui dati
Come visualizzare i dati utilizzando FusionCharts
In particolare, ciascuna delle sezioni ti porta un passo più vicino agli obiettivi di apprendimento:
Un'introduzione al dashboard meteo Questo capitolo fornisce una panoramica dei diversi aspetti dell'impresa.
Crea il progetto In questa sezione imparerai a creare un progetto da zero usando lo strumento da riga di comando Vue.
Personalizza la struttura del progetto predefinita L'impalcatura di progetto predefinita che ottieni nella sezione precedente non è sufficiente; qui impari le cose aggiuntive necessarie per il progetto da un punto di vista strutturale.
Acquisizione ed elaborazione dei dati Questa sezione è il fulcro del progetto; tutto il codice critico per l'acquisizione e l'elaborazione dei dati dall'API è mostrato qui. Aspettati di dedicare il massimo tempo a questa sezione.
Visualizzazione dei dati con FusionCharts Una volta stabilizzati tutti i dati e le altre parti mobili del progetto, questa sezione è dedicata alla visualizzazione dei dati utilizzando FusionCharts e un po' di CSS.
1. Il flusso di lavoro del dashboard
Prima di addentrarci nell'implementazione, è importante essere chiari sul nostro piano. Suddividiamo il nostro piano in quattro aspetti distinti:
Requisiti
Quali sono i nostri requisiti per questo progetto? In altre parole, quali sono le cose che vogliamo mostrare attraverso il nostro Weather Dashboard? Tenendo presente che il nostro pubblico previsto sono probabilmente semplici mortali con gusti semplici, vorremmo mostrare loro quanto segue:
Dettagli della località per la quale vogliono vedere il tempo, insieme ad alcune informazioni primarie sul tempo. Dal momento che non ci sono requisiti severi, scopriremo i dettagli noiosi in seguito. Tuttavia, in questa fase, è importante notare che dovremo fornire al pubblico una casella di ricerca, in modo che possano fornire input per la posizione di loro interesse.
Informazioni grafiche sul tempo della loro posizione di interesse, come ad esempio:
Variazione di temperatura per il giorno della richiesta
Aspetti del tempo di oggi:
Velocità e direzione del vento
Visibilità
Indice UV
Nota : i dati ottenuti dall'API forniscono informazioni su molti altri aspetti del tempo.Scegliamo di non usarli tutti per mantenere il codice al minimo.
Struttura
In base ai requisiti, possiamo strutturare la nostra dashboard come mostrato di seguito:
(Grande anteprima)
Dati
La nostra dashboard è buona quanto i dati che otteniamo, perché non ci saranno belle visualizzazioni senza dati adeguati. Esistono molte API pubbliche che forniscono dati meteorologici: alcune sono gratuite e altre no. Per il nostro progetto, raccoglieremo dati dall'API Dark Sky. Tuttavia, non saremo in grado di eseguire il polling dell'endpoint API direttamente dal lato client. Non preoccuparti, abbiamo una soluzione alternativa che verrà rivelata al momento giusto! Una volta ottenuti i dati per la posizione cercata, eseguiremo un po' di elaborazione e formattazione dei dati: il tipo di tecnicismi che ci aiuta a pagare le bollette.
Visualizzazione
Una volta ottenuti i dati puliti e formattati, li colleghiamo a FusionCharts. Ci sono pochissime librerie JavaScript al mondo capaci come FusionCharts. Tra il vasto numero di offerte di FusionCharts, ne utilizzeremo solo alcune, tutte scritte in JavaScript, ma funzionano perfettamente se integrate con il wrapper Vue per FusionCharts.
Armati del quadro più ampio, sporchiamoci le mani: è tempo di rendere le cose concrete! Nella prossima sezione creerai il progetto Vue di base, in cima al quale costruiremo ulteriormente.
2. Creazione del progetto
Per creare il progetto, eseguire i seguenti passaggi:
Installa Node.js + npm ( Se sul tuo computer è installato Node.js, salta questo passaggio. ) Node.js viene fornito con npm in bundle con esso, quindi non è necessario installare npm separatamente. A seconda del sistema operativo, scarica e installa Node.js secondo le istruzioni fornite qui.
Una volta installato, è probabilmente una buona idea verificare se il software funziona correttamente e quali sono le loro versioni. Per verificarlo, apri la riga di comando/terminale ed esegui i seguenti comandi:
node --version npm --version
Installa i pacchetti con npm Una volta che npm è attivo e funzionante, esegui il seguente comando per installare i pacchetti di base necessari per il nostro progetto.
npm install -g vue@2 vue-cli@2
Inizializza l'impalcatura del progetto con vue-cli Supponendo che il passaggio precedente sia andato tutto bene, il passaggio successivo consiste nell'utilizzare vue-cli , uno strumento da riga di comando di Vue.js, per inizializzare il progetto. Per fare ciò, eseguire quanto segue:
Inizializza l'impalcatura con il modello semplice di webpack.
vue init webpack-simple vue_weather_dashboard
Ti verranno poste un sacco di domande: accettare le impostazioni predefinite per tutti, ma l'ultima domanda sarà abbastanza buona per questo progetto; rispondi N per l'ultimo. (Grande anteprima) Tieni presente che, sebbene webpack-simple sia eccellente per la prototipazione rapida e per applicazioni leggere come la nostra, non è particolarmente adatto per applicazioni serie o per l'implementazione di produzione. Se vuoi usare qualsiasi altro modello (anche se ti sconsigliamo se sei un principiante), o se vuoi dare un nome al tuo progetto qualcos'altro, la sintassi è:
vue init [template-name] [project-name]
Passare alla directory creata da vue-cli per il progetto.
cd vue_weather_dashboard
Installa tutti i pacchetti menzionati in package.json , che è stato creato dallo strumento vue-cli per il modello webpack-simple .
npm install
Avvia il server di sviluppo e guarda il tuo progetto Vue predefinito che funziona nel browser!
npm run dev
Se non conosci Vue.js, prenditi un momento per assaporare il tuo ultimo traguardo: hai creato una piccola applicazione Vue ed è in esecuzione su localhost:8080!
(Grande anteprima)
Breve spiegazione della struttura di progetto predefinita
È ora di dare un'occhiata alla struttura all'interno della directory vue_weather_dashboard , in modo da avere una comprensione delle basi prima di iniziare a modificarla.
Anche se potrebbe essere allettante saltare l'acquisizione di familiarità con i file e le directory predefiniti, se non conosci Vue, ti consigliamo vivamente di dare almeno un'occhiata al contenuto dei file. Può essere una buona sessione educativa e innescare domande che dovresti perseguire da solo, in particolare i seguenti file:
package.json e solo uno sguardo a suo cugino package-lock.json
webpack.config.js
index.html
src/main.js
src/App.vue
Di seguito viene fornita una breve spiegazione di ciascuno dei file e delle directory mostrati nel diagramma ad albero:
LEGGIMI.md Nessun premio per indovinare: spetta principalmente agli esseri umani leggere e comprendere i passaggi necessari per creare l'impalcatura del progetto.
moduli_nodo/ Questa è la directory in cui npm scarica i pacchetti necessari per avviare il progetto. Le informazioni sui pacchetti necessari sono disponibili nel file package.json .
pacchetto.json Questo file viene creato dallo strumento vue-cli in base ai requisiti del modello webpack-simple e contiene informazioni sui pacchetti npm (incluse le relative versioni e altri dettagli) che devono essere installati. Dai un'occhiata al contenuto di questo file: è qui che dovresti visitare e forse modificare per aggiungere/eliminare i pacchetti necessari per il progetto, quindi eseguire npm install. Leggi di più su package.json qui.
pacchetto-lock.json Questo file è creato da npm stesso ed è pensato principalmente per mantenere un registro delle cose che npm ha scaricato e installato.
webpack.config.js Questo è un file JavaScript che contiene la configurazione di webpack, uno strumento che raggruppa diversi aspetti del nostro progetto (codice, risorse statiche, configurazione, ambienti, modalità di utilizzo, ecc.) e minimizza prima di servirlo all'utente. Il vantaggio è che tutte le cose sono collegate automaticamente e l'esperienza dell'utente migliora notevolmente grazie al miglioramento delle prestazioni dell'applicazione (le pagine vengono pubblicate rapidamente e si caricano più velocemente sul browser). Come potresti riscontrare in seguito, questo è il file che deve essere ispezionato quando qualcosa nel sistema di compilazione non funziona come dovrebbe essere. Inoltre, quando si desidera distribuire l'applicazione, questo è uno dei file chiave che deve essere modificato (leggi di più qui).
indice.html Questo file HTML funge da matrice (o, si può dire, modello) in cui i dati e il codice devono essere incorporati dinamicamente (questo è ciò che fa principalmente Vue) e quindi serviti all'utente.
src/main.js Questo file JavaScript contiene codice che gestisce principalmente le dipendenze di livello superiore/progetto e definisce il componente Vue di livello più alto. In breve, orchestra il JavaScript per l'intero progetto e funge da punto di ingresso dell'applicazione. Modifica questo file quando devi dichiarare dipendenze a livello di progetto su determinati moduli del nodo o vuoi che qualcosa venga modificato sul componente Vue più in alto nel progetto.
src/App.vue Nel punto precedente, quando si parlava del "componente Vue più in alto", si trattava essenzialmente di questo file. Ogni file .vue nel progetto è un componente e i componenti sono correlati gerarchicamente. All'inizio abbiamo un solo file .vue , cioè App.vue , come nostro unico componente. Ma a breve aggiungeremo altri componenti al nostro progetto (principalmente seguendo la struttura della dashboard) e li collegheremo secondo la nostra gerarchia desiderata, con App.vue che è l'antenato di tutti. Questi file .vue conterranno il codice in un formato che Vue vuole che scriviamo. Non preoccuparti, sono codice JavaScript scritto mantenendo una struttura che può mantenerci sani e organizzati. Sei stato avvisato: alla fine di questo progetto, se non conosci Vue, potresti diventare dipendente dal template — script — styletemplate — script — styletemplate — script — style di organizzazione del codice!
Ora che abbiamo creato le fondamenta, è il momento di:
Modifica i modelli e modifica leggermente i file di configurazione, in modo che il progetto si comporti esattamente come vogliamo.
Crea nuovi file .vue e implementa la struttura del dashboard con il codice Vue.
Li impareremo nella prossima sezione, che sarà un po' lunga e richiederà una certa attenzione. Se hai bisogno di caffeina o acqua, o vuoi scaricarti, ora è il momento!
3. Personalizzazione della struttura di progetto predefinita
È tempo di armeggiare con le basi che ci ha dato il progetto dell'impalcatura. Prima di iniziare, assicurati che il server di sviluppo fornito da webpack sia in esecuzione. Il vantaggio dell'esecuzione continua di questo server è che qualsiasi modifica apportata al codice sorgente, salvandolo e aggiornando la pagina Web, si riflette immediatamente sul browser.
Se vuoi avviare il server di sviluppo, esegui semplicemente il seguente comando dal terminale (supponendo che la tua directory corrente sia la directory del progetto):
npm run dev
Nelle sezioni seguenti, modificheremo alcuni dei file esistenti e aggiungeremo alcuni nuovi file. Sarà seguito da brevi spiegazioni del contenuto di quei file, in modo da avere un'idea di cosa dovrebbero fare queste modifiche.
Modifica file esistenti
indice.html
La nostra applicazione è letteralmente un'applicazione a pagina singola, perché c'è solo una pagina web che viene visualizzata sul browser. Ne parleremo più avanti, ma prima apportiamo la nostra prima modifica: alterare il testo all'interno del tag <title> .
Con questa piccola revisione, il file HTML è simile al seguente:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <!-- Modify the text of the title tag below --> <title>Vue Weather Dashboard</title> </head> <body> <div></div> <script src="/dist/build.js"></script> </body> </html>
Prenditi un momento per aggiornare la pagina web su localhost:8080 e osserva la modifica riflessa sulla barra del titolo della scheda del browser: dovrebbe dire "Vue Weather Dashboard". Tuttavia, questo era solo per mostrarti il processo di apportare modifiche e verificare se funziona. Abbiamo più cose da fare!
Questa semplice pagina HTML manca di molte cose che vogliamo nel nostro progetto, in particolare le seguenti:
Alcune metainformazioni
Collegamenti CDN a Bootstrap (framework CSS)
collegamento al foglio di stile personalizzato (ancora da aggiungere nel progetto)
Puntatori all'API di geolocalizzazione di Google Maps dal tag <script>
Dopo aver aggiunto queste cose, l' index.html ha il seguente contenuto:
Salva il file e aggiorna la pagina web. Potresti aver notato un leggero urto durante il caricamento della pagina: è principalmente dovuto al fatto che lo stile della pagina è ora controllato da Bootstrap e gli elementi di stile come caratteri, spaziatura, ecc. Sono diversi da quelli predefiniti che avevamo prima (se non sei sicuro, torna all'impostazione predefinita e vedi la differenza).
(Grande anteprima)
Nota : una cosa importante prima di andare avanti: l'URL dell'API di Google Maps contiene una chiave che è una proprietà di FusionCharts.Per ora, puoi usare questa chiave per costruire il progetto, poiché non vogliamo che ti impantani in questo tipo di dettagli minuti (che possono essere distrazioni mentre sei nuovo).Tuttavia, ti esortiamo vivamente a generare e utilizzare la tua chiave API di Google Maps una volta che hai fatto alcuni progressi e ti senti a tuo agio nel prestare attenzione a questi piccoli dettagli.
pacchetto.json
Al momento della stesura di questo, abbiamo utilizzato alcune versioni dei pacchetti npm per il nostro progetto e sappiamo per certo che queste cose funzionano insieme. Tuttavia, nel momento in cui esegui il progetto, è molto probabile che le ultime versioni stabili dei pacchetti che npm scarica per te non siano le stesse che abbiamo usato e questo potrebbe rompere il codice (o fare cose che vanno oltre il nostro controllo). Pertanto, è molto importante avere lo stesso identico file package.json utilizzato per creare questo progetto, in modo che il nostro codice/spiegazioni e i risultati ottenuti siano coerenti.
Il contenuto del file package.json dovrebbe essere:
Ti invitiamo a esaminare il nuovo package.json e capire quali sono le funzioni dei diversi oggetti nel json. Potresti preferire cambiare il valore della chiave " author " con il tuo nome. Inoltre, i pacchetti menzionati nelle dipendenze si riveleranno al momento giusto nel codice. Per il momento è sufficiente sapere che:
i pacchetti relativi a babel servono per gestire correttamente il codice di stile ES6 dal browser;
axios si occupa delle richieste HTTP basate su Promise;
moment e momento-fuso orario sono per la manipolazione di data/ora;
fusioncharts e vue-fusioncharts sono responsabili del rendering dei grafici:
vue , per ovvi motivi.
webpack.config.js
Come per package.json , ti suggeriamo di mantenere un file webpack.config.js coerente con quello che abbiamo usato per costruire il progetto. Tuttavia, prima di apportare modifiche, ti consigliamo di confrontare attentamente il codice predefinito in webpack.config.js e il codice che abbiamo fornito di seguito. Noterai alcune differenze: cercale su Google e avrai un'idea di base di cosa significano. Poiché la spiegazione approfondita delle configurazioni del webpack non rientra nell'ambito di questo articolo, a questo proposito sei da solo.
Il file webpack.config.js personalizzato è il seguente:
Con le modifiche apportate al webpack.config.js del progetto, è imperativo arrestare il server di sviluppo in esecuzione ( Ctrl + C ) e riavviarlo con il seguente comando eseguito dalla directory del progetto dopo aver installato tutti i pacchetti menzionati nel package.json File package.json :
npm install npm run dev
Con questo, finisce il calvario di modificare le configurazioni e garantire che i pacchetti giusti siano a posto. Tuttavia, questo segna anche il viaggio di modifica e scrittura del codice, che è un po' lungo ma anche molto gratificante!
src/main.js
Questo file è la chiave per l'orchestrazione di alto livello del progetto: è qui che definiamo:
Quali sono le dipendenze di livello superiore (dove ottenere i pacchetti npm più importanti necessari);
Come risolvere le dipendenze, insieme alle istruzioni per Vue sull'uso di plugin/wrapper, se presenti;
Un'istanza Vue che gestisce il componente più in alto nel progetto: src/App.vue (il file .vue nodale).
In linea con i nostri obiettivi per il file src/main.js , il codice dovrebbe essere:
// Import the dependencies and necessary modules import Vue from 'vue'; import App from './App.vue'; import FusionCharts from 'fusioncharts'; import Charts from 'fusioncharts/fusioncharts.charts'; import Widgets from 'fusioncharts/fusioncharts.widgets'; import PowerCharts from 'fusioncharts/fusioncharts.powercharts'; import FusionTheme from 'fusioncharts/themes/fusioncharts.theme.fusion'; import VueFusionCharts from 'vue-fusioncharts'; // Resolve the dependencies Charts(FusionCharts); PowerCharts(FusionCharts); Widgets(FusionCharts); FusionTheme(FusionCharts); // Globally register the components for project-wide use Vue.use(VueFusionCharts, FusionCharts); // Instantiate the Vue instance that controls the application new Vue({ el: '#app', render: h => h(App) })
src/App.vue
Questo è uno dei file più importanti dell'intero progetto e rappresenta il componente più in alto nella gerarchia: l'intera applicazione stessa, nel suo insieme. Per il nostro progetto, questo componente farà tutto il lavoro pesante, che esploreremo in seguito. Per ora, vogliamo sbarazzarci del boilerplate predefinito e inserire qualcosa di nostro.
Se sei nuovo nel modo in cui Vue organizza il codice, sarebbe meglio avere un'idea della struttura generale all'interno dei file .vue . I file .vue sono composti da tre sezioni:
Modello Qui è dove viene definito il modello HTML per la pagina. Oltre all'HTML statico, questa sezione contiene anche il modo in cui Vue incorpora il contenuto dinamico, usando le doppie parentesi graffe {{ }} .
copione JavaScript governa questa sezione ed è responsabile della generazione di contenuto dinamico che va e si trova all'interno del modello HTML nei punti appropriati. Questa sezione è principalmente un oggetto che viene esportato ed è composta da:
Dati Questa è una funzione stessa e di solito restituisce alcuni dati desiderati incapsulati all'interno di una bella struttura di dati.
Metodi Un oggetto costituito da una o più funzioni/metodi, ognuno dei quali di solito manipola i dati in un modo o nell'altro, e controlla anche il contenuto dinamico del modello HTML.
Calcolato Proprio come l'oggetto metodo discusso sopra con un'importante distinzione: mentre tutte le funzioni all'interno dell'oggetto metodo vengono eseguite ogni volta che viene chiamata una di esse, le funzioni all'interno dell'oggetto calcolato si comportano in modo molto più sensato ed vengono eseguite se e solo se è stato chiamata.
Stile Questa sezione è per lo stile CSS che si applica all'HTML della pagina (scritto all'interno del modello): metti qui il buon vecchio CSS per rendere belle le tue pagine!
Tenendo presente il paradigma sopra, personalizziamo minimamente il codice in App.vue :
Ricorda che il frammento di codice sopra è semplicemente per testare che App.vue sta lavorando con il nostro codice al suo interno. In seguito andrà avanti attraverso molte modifiche, ma prima salverà il file e aggiornerà la pagina sul browser.
(Grande anteprima)
A questo punto, è probabilmente una buona idea chiedere aiuto per gli utensili. Dai un'occhiata agli strumenti di sviluppo Vue per Chrome e, se non hai molti problemi nell'utilizzo di Google Chrome come browser predefinito per lo sviluppo, installa lo strumento e giocaci un po'. Sarà estremamente utile per ulteriori sviluppi e debug, quando le cose si complicano.
Directory e file aggiuntivi
Il passo successivo sarebbe aggiungere file aggiuntivi, in modo che la struttura del nostro progetto diventi completa. Aggiungeremmo le seguenti directory e file:
Nota : salva i file .svg con collegamento ipertestuale nel tuo progetto.
Crea le directory e i file sopra menzionati. La struttura del progetto finale dovrebbe essere simile all'aspetto (ricorda di eliminare le cartelle e i file dalla struttura predefinita che ora non sono necessari):
Potrebbero esserci altri file, come.babelrc , .gitignore , .editorconfig , ecc. Nella cartella principale del progetto.Puoi ignorarli in sicurezza per ora.
Nella sezione seguente, aggiungeremo contenuto minimo ai file appena aggiunti e verificheremo se funzionano correttamente.
src/css/style.css
Anche se non sarà di grande utilità immediatamente, copia il codice seguente nel file:
In questa directory, scarica e salva i file .svg indicati di seguito:
calendar.svg
location.svg
search.svg
winddirection.svg
windspeed.svg
src/components/Content.vue
Questo è ciò che chiamiamo un "componente stupido" (cioè un segnaposto) che è lì solo per mantenere la gerarchia, ed essenzialmente trasmette i dati ai suoi componenti figli.
Ricorda che non esiste una barra tecnica per scrivere tutto il nostro codice nel file App.vue , ma adottiamo l'approccio di suddividere il codice annidando i componenti per due motivi:
Per scrivere codice pulito, che aiuta la leggibilità e la manutenibilità;
Per replicare la stessa struttura che vedremo sullo schermo, ovvero la gerarchia.
Prima di annidare il componente definito in Content.vue all'interno del componente root App.vue , scriviamo del codice giocattolo (ma educativo) per Content.vue :
Nel codice, osservare attentamente e comprendere quanto segue:
All'interno del tag <script> (dove ovviamente scriviamo del codice JavaScript), definiamo un oggetto che viene esportato (reso disponibile ad altri file) di default. Questo oggetto contiene una funzione data() , che restituisce un oggetto array chiamato childComponents , con i suoi elementi che sono i nomi dei file dei componenti che dovrebbero essere ulteriormente nidificati.
All'interno del tag <template> (dove scriviamo dei template HTML), la cosa di interesse è il <ul> .
All'interno dell'elenco non ordinato, ogni elemento dell'elenco dovrebbe essere il nome dei componenti figlio previsti, come definito nell'oggetto array childComponents . Inoltre, l'elenco dovrebbe estendersi automaticamente fino all'ultimo elemento dell'array. Sembra che dovremmo scrivere un ciclo for , vero? Lo facciamo utilizzando la direttiva v-for fornita da Vue.js. La direttiva v-for :
Agisce come un attributo del tag <li> , scorre l'array, esegue il rendering dei nomi dei componenti figlio in cui l'iteratore è menzionato all'interno delle parentesi {{ }} (dove scriviamo il testo per gli elementi dell'elenco).
Il codice e la spiegazione di cui sopra costituiscono la base della tua successiva comprensione di come lo script e il modello sono correlati e come possiamo utilizzare le direttive fornite da Vue.js.
Abbiamo imparato parecchio, ma anche dopo tutto questo, abbiamo ancora una cosa da imparare sulla connessione perfetta dei componenti nella gerarchia: passare i dati dal componente genitore ai suoi figli. Per ora, dobbiamo imparare come passare alcuni dati da src/App.vue a src/components/Content.vue , in modo da poter utilizzare le stesse tecniche per il resto della nidificazione dei componenti in questo progetto.
I dati che scendono dai componenti genitore a quelli figli possono sembrare semplici, ma il diavolo è nei dettagli! Come spiegato brevemente di seguito, ci sono più passaggi necessari per farlo funzionare:
La definizione ei dati Per ora, vogliamo alcuni dati statici con cui giocare: un oggetto contenente valori codificati su diversi aspetti del tempo andrà benissimo! Creiamo un oggetto chiamato weather_data e lo restituiamo dalla funzione data() di App.vue . L'oggetto weather_data è fornito nello snippet di seguito:
Passaggio dei dati dal genitore Per trasmettere i dati, abbiamo bisogno di una destinazione a cui vogliamo inviare i dati! In questo caso, la destinazione è il componente Content.vue e il modo per implementarlo è:
Assegna l'oggetto weather_data a un attributo personalizzato del tag <Content>
Associa l'attributo ai dati utilizzando la direttiva v-bind : fornita da Vue.js, che rende dinamico il valore dell'attributo (reattivo alle modifiche apportate ai dati originali).
Con i dati definiti e passati dalla fonte (componente genitore), è ora responsabilità del bambino ricevere i dati e renderli in modo appropriato, come spiegato nei due passaggi successivi.
Ricezione dei dati da parte del bambino Il componente figlio, in questo caso Content.vue , deve ricevere l'oggetto weather_data inviatogli dal componente padre App.vue . Vue.js fornisce un meccanismo per farlo: tutto ciò di cui hai bisogno è un oggetto array chiamato props , definito nell'oggetto predefinito esportato da Content.vue . Ogni elemento degli props di scena dell'array è un nome degli oggetti dati che desidera ricevere dal suo genitore. Per ora, l'unico oggetto dati che dovrebbe ricevere è weather_data da App.vue. Pertanto, l'array props è simile a:
<template> // HTML template code here </template> <script> export default { props: ["weather_data"], data () { return { // data here } }, } </script> <style> // component specific CSS here </style>
Rendering dei dati nella pagina Ora che ci siamo assicurati di ricevere i dati, l'ultima attività che dobbiamo completare è il rendering dei dati. Per questo esempio, scaricheremo direttamente i dati ricevuti sulla pagina web, solo per illustrare la tecnica. Tuttavia, nelle applicazioni reali (come quella che stiamo per costruire), i dati normalmente subiscono molte elaborazioni e solo le parti rilevanti di essi vengono visualizzate in modi adatti allo scopo. Ad esempio, in questo progetto otterremo i dati grezzi dall'API meteo, li puliremo e formatteremo, alimenteremo i dati alle strutture dati necessarie per i grafici e quindi li visualizzeremo. Ad ogni modo, per visualizzare il dump dei dati grezzi, utilizzeremo semplicemente le parentesi {{ }} che Vue comprende, come mostrato nello snippet di seguito:
<template> <div> // other template code here {{ weather_data }} </div> </template>
È giunto il momento di assimilare tutti i frammenti. Il codice per Content.vue , allo stato attuale, è riportato di seguito:
Dopo aver apportato le modifiche discusse sopra, aggiorna la pagina Web sul browser e guarda come appare. Prenditi un momento per apprezzare la complessità gestita da Vue: se modifichi l'oggetto weather_data in App.vue , viene trasmesso silenziosamente a Content.vue e, infine, al browser che visualizza la pagina web! Prova a modificare il valore per la posizione della chiave.
Sebbene abbiamo appreso di prop e data binding utilizzando dati statici, utilizzeremo i dati dinamici raccolti utilizzando le API Web nell'applicazione e modificheremo il codice di conseguenza .
Sommario
Prima di passare al resto dei file .vue , riassumiamo ciò che abbiamo imparato mentre scrivevamo il codice per App.vue e components/Content.vue :
Il file App.vue è ciò che chiamiamo il componente principale, quello che si trova in cima alla gerarchia dei componenti. Il resto dei file .vue rappresenta i componenti che sono il figlio diretto, il nipote e così via.
Il file Content.vue è un componente fittizio: la sua responsabilità è trasmettere i dati ai livelli inferiori e mantenere la gerarchia strutturale, in modo che il nostro codice rimanga coerente con la filosofia "*ciò che vediamo è ciò che implementiamo*".
La relazione padre-figlio del componente non avviene dal nulla: è necessario registrare un componente (a livello globale o locale, a seconda dell'uso previsto del componente) e quindi nidificarlo utilizzando tag HTML personalizzati (la cui ortografia è l'esatta uguale a quello delle denominazioni con cui i componenti sono stati registrati).
Una volta registrati e nidificati, i dati vengono passati dai componenti padre a quelli figlio e il flusso non è mai inverso (se l'architettura del progetto consente il riflusso accadranno cose brutte). Il componente padre è l'origine relativa dei dati e trasmette i dati rilevanti ai suoi figli utilizzando la direttiva v-bind per gli attributi degli elementi HTML personalizzati. Il bambino riceve i dati a lui destinati utilizzando oggetti di scena e quindi decide da solo cosa fare con i dati.
Per il resto dei componenti, non ci abbandoneremo a spiegazioni dettagliate: scriveremo semplicemente il codice in base a quanto appreso dal riepilogo sopra. Il codice sarà evidente e, se ti confondi sulla gerarchia, fai riferimento al diagramma seguente:
(Grande anteprima)
Il diagramma dice che TempVarChart.vue e Highlights.vue sono il figlio diretto di Content.vue . Pertanto, potrebbe essere una buona idea preparare Content.vue per l'invio di dati a quei componenti, cosa che facciamo usando il codice seguente:
Una volta salvato questo codice, otterrai errori: non preoccuparti, è previsto. Verrà risolto una volta che avrai pronto il resto dei file dei componenti. Se ti dà fastidio non essere in grado di vedere l'output, commenta le righe contenenti i tag dell'elemento personalizzato <temp-var-chart> e <today-highlights> .
Per questa sezione, questo è il codice finale di Content.vue . Per il resto di questa sezione, faremo riferimento a questo codice e non ai precedenti che abbiamo scritto per l'apprendimento.
src/components/TempVarChart.vue
Con il suo componente padre Content.vue che trasmette i dati, TempVarChart.vue deve essere impostato per ricevere e rendere i dati, come mostrato nel codice seguente:
Questo componente riceverà anche i dati da App.vue , il suo componente principale. Successivamente, dovrebbe essere collegato ai suoi componenti figlio e i dati pertinenti dovrebbero essere trasmessi a loro.
Vediamo prima il codice per la ricezione dei dati dal genitore:
A questo punto, la pagina web appare come l'immagine qui sotto:
(Grande anteprima)
Ora dobbiamo modificare il codice di Highlights.vue per registrare e annidare i suoi componenti figlio, quindi passare i dati ai bambini. Il codice per esso è il seguente:
Una volta salvato il codice e visualizzata la pagina Web, dovresti visualizzare errori nello strumento Developer Console fornito dal browser; appaiono perché sebbene Highlights.vue stia inviando dati, nessuno li sta ricevendo. Dobbiamo ancora scrivere il codice per i bambini di Highlights.vue .
Si noti che non abbiamo svolto gran parte dell'elaborazione dei dati, ovvero non abbiamo estratto i singoli fattori dei dati meteorologici che si trovano nella sezione In evidenza della dashboard. Avremmo potuto farlo nella funzione data() , ma abbiamo preferito mantenere Highlights.vue un componente stupido che trasmette semplicemente l'intero dump dei dati che riceve a ciascuno dei bambini, che quindi possiede le proprie estrae ciò che è necessario per loro . Tuttavia, ti invitiamo a provare a estrarre i dati in Highlights.vue e a inviare i dati pertinenti a ciascun componente figlio: è comunque un esercizio di buona pratica!
src/components/UVIndex.vue
Il codice per questo componente riceve il dump dei dati degli highlights da Highlights.vue , estrae i dati per l'indice UV e li visualizza nella pagina.
Il codice per questo componente riceve il dump dei dati degli highlights da Highlights.vue , estrae i dati per Visibility e ne esegue il rendering sulla pagina.
Il codice per questo componente riceve il dump dei dati degli highlights da Highlights.vue , estrae i dati per lo stato del vento (velocità e direzione) e li visualizza nella pagina.
Dopo aver aggiunto il codice di tutti i componenti, dai un'occhiata alla pagina web del browser.
(Grande anteprima)
Non per scoraggiare, ma tutte queste fatiche erano solo per collegare i componenti nella gerarchia e testare se il flusso di dati sta avvenendo tra di loro o meno! Nella prossima sezione, getteremo via la maggior parte del codice che abbiamo scritto finora e aggiungeremo molto altro relativo al progetto vero e proprio. Tuttavia, manterremo sicuramente la struttura e l'annidamento dei componenti; gli insegnamenti di questa sezione ci consentiranno di creare una dashboard decente con Vue.js.
4. Acquisizione ed elaborazione dei dati
Ricordi l'oggetto weather_data in App.vue ? Aveva alcuni dati codificati che abbiamo usato per testare se tutti i componenti funzionano correttamente e anche per aiutarti ad apprendere alcuni aspetti di base dell'applicazione Vue senza impantanarsi nei dettagli dei dati del mondo reale. Tuttavia, è giunto il momento di liberarci della nostra shell ed entrare nel mondo reale, dove i dati dell'API domineranno la maggior parte del nostro codice.
Preparazione dei componenti figlio per ricevere ed elaborare dati reali
In questa sezione, otterrai il dump del codice per tutti i componenti tranne App.vue . Il codice gestirà la ricezione di dati reali da App.vue (a differenza del codice che abbiamo scritto nella sezione precedente per ricevere e renderizzare dati fittizi).
Incoraggiamo vivamente a leggere attentamente il codice di ogni componente, in modo da farti un'idea di quali dati ciascuno di quei componenti si aspetta e che alla fine utilizzerà nella visualizzazione.
Parte del codice e la struttura generale saranno simili a quelli che hai visto nella struttura precedente, quindi non dovrai affrontare qualcosa di drasticamente diverso. Tuttavia, il diavolo è nei dettagli! Quindi esamina attentamente il codice e, dopo averlo compreso abbastanza bene, copia il codice nei rispettivi file dei componenti del tuo progetto.
Nota : tutti i componenti di questa sezione si trovano nella directory src/components/ .Pertanto, ogni volta, il percorso non verrà menzionato: verrà menzionato solo il nome del file .vue per identificare il componente.
Rispetto al codice precedente sono state apportate le seguenti modifiche:
Nel <template> , testo e dati all'interno di {{ }} sono stati rimossi, poiché ora stiamo solo ricevendo dati e trasmettendoli ai bambini, senza rendere questo componente specifico.
Nel export default {} :
Gli props di scena sono stati modificati per corrispondere agli oggetti dati che verranno inviati dal genitore: App.vue . Il motivo per modificare gli oggetti di scena è che App.vue stesso mostrerà alcuni dei dati che acquisisce dall'API meteo e altre risorse online, in base alla query di ricerca dell'utente, e trasmetterà il resto dei dati. Nel codice fittizio che abbiamo scritto in precedenza, App.vue trasmetteva l'intero dump di dati fittizi, senza alcuna discriminazione, e gli oggetti di scena di Content.vue erano impostati di conseguenza.
La funzione data() ora non restituisce nulla, poiché non stiamo facendo alcuna manipolazione dei dati in questo componente.
TempVarChart.vue
Questo componente dovrebbe ricevere proiezioni dettagliate della temperatura per il resto della giornata corrente e, infine, visualizzarle utilizzando FusionCharts. Ma per il momento, li visualizzeremo solo come testo sulla pagina web.
Nel <template> , il testo e i dati all'interno di {{ }} sono stati rimossi, perché questo è un componente stupido, proprio come Content.vue , il cui unico compito è trasmettere i dati ai bambini mantenendo la gerarchia strutturale. Ricorda che i componenti stupidi come Highlights.vue e Content.vue esistono per mantenere la parità tra la struttura visiva della dashboard e il codice che scriviamo.
UVIndex.vue
Le modifiche apportate al codice precedente sono le seguenti:
In <template> e <style> , il div id è stato modificato in uvIndex , che è più leggibile.
In export default {} , la funzione data() ora restituisce un oggetto stringa uvIndex , il cui valore viene estratto dall'oggetto highlights ricevuto dal componente usando props . Questo uvIndex è ora temporaneamente utilizzato per visualizzare il valore come testo all'interno del <template> . Successivamente, collegheremo questo valore alla struttura dati adatta per il rendering di un grafico.
L'unica modifica apportata a questo file (rispetto al suo codice precedente) è che la definizione dell'oggetto di visibility restituito dalla funzione data() contiene ora toString() alla sua fine, poiché il valore ricevuto dal genitore sarà un floating numero di punto, che deve essere convertito in stringa.
WindStatus.vue
<template> <div> <p>Wind Speed — {{ windSpeed }}</p> <p>Wind Direction — {{ derivedWindDirection }}, or {{ windDirection }} degree clockwise with respect to true N as 0 degree.</p> </div> </template> <script> export default { props: ["highlights"], data () { return { windSpeed: this.highlights.windStatus.windSpeed, derivedWindDirection: this.highlights.windStatus.derivedWindDirection, windDirection: this.highlights.windStatus.windDirection } }, methods: { }, computed: { }, } </script> <style> </style>
Le modifiche apportate al codice precedente sono le seguenti:
In tutto il file, windstatus è stato rinominato windStatus , per promuovere la leggibilità e anche per essere sincronizzato con l'oggetto highlights che App.vue fornisce con i dati effettivi.
Simili modifiche alla denominazione sono state apportate per la velocità e la direzione: le nuove sono windSpeed e windDirection .
È entrato in gioco un nuovo oggetto derivatoWindDirection (fornito anche da derivedWindDirection nel App.vue highlights).
Per ora, i dati ricevuti vengono visualizzati come testo; successivamente, verrà inserito nella struttura dati necessaria per la visualizzazione.
Test con dati fittizi
Ricorrere ripetutamente a dati fittizi potrebbe essere un po' frustrante per te, ma ci sono alcune buone ragioni dietro:
Abbiamo apportato molte modifiche al codice di ogni componente ed è una buona idea verificare se tali modifiche stanno violando il codice. In altre parole, dovremmo verificare che il flusso di dati sia integro, ora che stiamo per passare a parti più complesse del progetto.
I dati reali dell'API meteo online avranno bisogno di molto massaggio e potrebbe essere opprimente per te destreggiarti tra il codice per l'acquisizione e l'elaborazione dei dati e il codice per un flusso fluido dei dati lungo i componenti. L'idea è di tenere sotto controllo il quanto di complessità, in modo da avere una migliore comprensione degli errori che potremmo incontrare.
In questa sezione, ciò che facciamo essenzialmente è codificare alcuni dati json in App.vue , che ovviamente verranno sostituiti con dati live nel prossimo futuro. Ci sono molte somiglianze tra la struttura json fittizia e la struttura json che useremo per i dati effettivi. Quindi ti fornisce anche un'idea approssimativa di cosa aspettarti dai dati reali, una volta che li incontriamo.
Tuttavia, ammettiamo che questo è tutt'altro che l'approccio ideale che si potrebbe adottare mentre si costruisce un progetto del genere da zero. Nel mondo reale, inizierai spesso con l'origine dati reale, ci giocherai un po' per capire cosa si può e si dovrebbe fare per domarla, quindi pensare alla struttura di dati json appropriata per acquisire le informazioni rilevanti. Ti abbiamo protetto intenzionalmente da tutto quel lavoro sporco, poiché ti porta più lontano dall'obiettivo: imparare a usare Vue.js e FusionCharts per costruire una dashboard.
Le modifiche apportate al codice rispetto alla sua versione precedente sono le seguenti:
Il nome del componente figlio è stato modificato in dashboard-content e di conseguenza l'elemento HTML personalizzato nel <template> è stato rivisto. Nota che ora abbiamo due attributi - highlights e tempVar - invece di un singolo attributo che abbiamo usato in precedenza con l'elemento personalizzato. Di conseguenza, anche i dati associati a tali attributi sono cambiati. La cosa interessante qui è che possiamo usare la direttiva v-bind: :, o la sua scorciatoia : (come abbiamo fatto qui), con più attributi di un elemento HTML personalizzato!
La funzione data() ora restituisce l'oggetto filename (che esisteva in precedenza), insieme a due nuovi oggetti (invece dei vecchi weather_data ): tempVar e highlights . La struttura del json è appropriata per il codice che abbiamo scritto nei componenti figlio, in modo che possano estrarre i dati di cui hanno bisogno dai dump. Le strutture sono abbastanza autoesplicative e puoi aspettarti che siano abbastanza simili quando trattiamo dati in tempo reale. Tuttavia, il cambiamento significativo che incontrerai è l'assenza di hardcoding (ovvio, non è vero): lasceremo i valori vuoti come stato predefinito e scriveremo il codice per aggiornarli dinamicamente in base ai valori che riceveremo dal API meteo.
Hai scritto molto codice in questa sezione, senza vedere l'output effettivo. Prima di procedere ulteriormente, dai un'occhiata al browser (riavvia il server con npm run dev , se necessario) e goditi la gloria del tuo risultato. La pagina web che dovresti vedere a questo punto è simile all'immagine qui sotto:
(Grande anteprima)
Codice per l'acquisizione e il trattamento dei dati
Questa sezione sarà il fulcro del progetto, con tutto il codice da scrivere in App.vue per quanto segue:
Input della posizione da parte dell'utente: sono sufficienti una casella di input e un pulsante di invito all'azione;
Funzioni di utilità per vari compiti; queste funzioni verranno richiamate successivamente in varie parti del codice componente;
Ottenere dati di geolocalizzazione dettagliati dall'API di Google Maps per JavaScript;
Ottenere dati meteorologici dettagliati dall'API Dark Sky;
Formattazione ed elaborazione dei dati di geolocalizzazione e meteo, che verranno trasmessi ai componenti figlio.
Le sottosezioni che seguono illustrano come possiamo attuare i compiti previsti per noi nei punti precedenti. Con alcune eccezioni, la maggior parte seguirà la sequenza.
Input dall'utente
È abbastanza ovvio che l'azione inizia quando l'utente fornisce il nome del luogo per il quale devono essere visualizzati i dati meteorologici. Affinché ciò avvenga, è necessario implementare quanto segue:
Una casella di input per inserire la posizione;
Un pulsante di invio che dice alla nostra applicazione che l'utente ha inserito la posizione ed è ora di fare il resto. Implementeremo anche il comportamento all'avvio dell'elaborazione dopo aver premuto Invio .
Il codice che mostriamo di seguito sarà limitato alla parte del modello HTML di App.vue . Ci limiteremo a citare il nome del metodo associato agli eventi click e li definiremo successivamente nell'oggetto metodi dello <script> in App.vue.
Posizionare lo snippet sopra nel posto giusto è banale: lo lasciamo a te. Tuttavia, le parti interessanti dello snippet sono:
@keyup.enter="organizeAllDetails"
@click="organizeAllDetails"
Come saprai dalle sezioni precedenti, @ è l'abbreviazione di Vue per la direttiva v-on :, che è associata a qualche evento. La novità è " organizeAllDetails " — non è altro che il metodo che si attiverà una volta che si verificano gli eventi (premendo Invio o facendo clic sul pulsante). Dobbiamo ancora definire il metodo e il puzzle sarà completo entro la fine di questa sezione.
Visualizzazione delle informazioni di testo controllata da App.vue
Una volta che l'input dell'utente attiva l'azione e molti dati vengono acquisiti dalle API, ci imbattiamo nell'inevitabile domanda: "Cosa fare con tutti questi dati?". Ovviamente è richiesto un po 'di massaggio dei dati, ma ciò non risponde completamente alla nostra domanda! Dobbiamo decidere qual è l'uso finale dei dati, o più direttamente, quali sono le entità che ricevono diversi blocchi dei dati acquisiti ed elaborati?
I componenti figlio di App.vue , in base alla loro gerarchia e scopo, sono i contendenti in prima linea per la maggior parte dei dati. Tuttavia, avremo anche alcuni dati che non appartengono a nessuno di questi componenti secondari, ma sono piuttosto informativi e completano la dashboard. Possiamo farne un buon uso se li mostriamo come informazioni di testo direttamente controllate da App.vue , mentre il resto dei dati viene passato al bambino per essere infine visualizzato come graziosi grafici.
Tenendo presente questo contesto, concentriamoci sul codice per impostare la fase di utilizzo dei dati di testo. È un semplice modello HTML a questo punto, su cui i dati alla fine arriveranno e si posizioneranno.
Nello snippet sopra, dovresti capire quanto segue:
Le cose all'interno di {{ }} : sono il modo in cui Vue inserisce dati dinamici nel modello HTML, prima che vengano visualizzati nel browser. Li hai già incontrati e non c'è nulla di nuovo o sorprendente. Tieni presente che questi oggetti dati derivano dal metodo data() () nell'oggetto export default() di App.vue . Hanno valori predefiniti che imposteremo in base ai nostri requisiti, quindi scriveremo determinati metodi per popolare gli oggetti con dati API reali.
Non preoccuparti di non vedere le modifiche sul browser: i dati non sono ancora definiti ed è naturale che Vue non visualizzi cose che non conosce. Tuttavia, una volta impostati i dati (e per ora puoi anche controllare i dati tramite hardcoding), i dati di testo saranno controllati da App.vue .
Il metodo data()
Il metodo data() è un costrutto speciale nei file .vue : contiene e restituisce oggetti dati che sono così cruciali per l'applicazione. Ricorda la struttura generica della parte <script> in qualsiasi file .vue — contiene approssimativamente quanto segue:
<script> // import statements here export default { // name, components, props, etc. data() { return { // the data that is so crucial for the application is defined here. // the data objects will have certain default values chosen by us. // The methods that we define below will manipulate the data. // Since the data is bounded to various attributes and directives, they // will update as and when the values of the data objects change. } }, methods: { // methods (objects whose values are functions) here. // bulk of dynamic stuff (the black magic part) is controlled from here. }, computed: { // computed properties here }, // other objects, as necessary } </script>
Finora, hai incontrato i nomi di alcuni oggetti dati, ma sono molti di più. La maggior parte di essi è rilevante per i componenti figlio, ognuno dei quali gestisce un aspetto diverso del dump delle informazioni meteorologiche. Di seguito è riportato l'intero metodo data() di cui avremo bisogno per questo progetto: avrai una buona idea di quali dati ci aspettiamo dalle API e di come stiamo diffondendo i dati, in base alla nomenclatura degli oggetti.
data() { return { weatherDetails: false, location: '', // raw location from input lat: '', // raw latitude from google maps api response long: '', // raw longitude from google maps api response completeWeatherApi: '', // weather api string with lat and long rawWeatherData: '', // raw response from weather api currentWeather: { full_location: '', // for full address formatted_lat: '', // for N/S formatted_long: '', // for E/W time: '', temp: '', todayHighLow: { todayTempHigh: '', todayTempHighTime: '', todayTempLow: '', todayTempLowTime: '' }, summary: '', possibility: '' }, tempVar: { tempToday: [ // gets added dynamically by this.getSetHourlyTempInfoToday() ], }, highlights: { uvIndex: '', visibility: '', windStatus: { windSpeed: '', windDirection: '', derivedWindDirection: '' }, } }; },
Come puoi vedere, nella maggior parte dei casi il valore predefinito è vuoto, perché a questo punto sarà sufficiente. Verranno scritti metodi per manipolare i dati e riempirli con valori appropriati, prima che vengano visualizzati o trasmessi ai componenti figlio.
Metodi in App.vue
Per i file .vue , i metodi sono generalmente scritti come valori di chiavi annidate nell'oggetto methods { } . Il loro ruolo principale è manipolare gli oggetti dati del componente. Scriveremo i metodi in App.vue tenendo presente la stessa filosofia. Tuttavia, in base al loro scopo, possiamo classificare i metodi di App.vue come segue:
Metodi di utilità
Metodi orientati all'azione/evento
Metodi di acquisizione dati
Modalità di trattamento dei dati
Metodi di colla di alto livello
È importante che tu lo capisca: ti presentiamo i metodi su un piatto perché abbiamo già capito come funzionano le API, quali dati forniscono e come dovremmo utilizzare i dati nel nostro progetto. Non è che abbiamo tirato fuori i metodi dal nulla e scritto del codice arcano per gestire i dati. Ai fini dell'apprendimento, è un buon esercizio leggere e comprendere diligentemente il codice per i metodi e i dati. Tuttavia, di fronte a un nuovo progetto che devi costruire da zero, devi fare tutto il lavoro sporco da solo, e questo significa sperimentare molto con le API, il loro accesso programmatico e la loro struttura dei dati, prima di incollarle perfettamente con i dati struttura che il tuo progetto richiede. Non avrai nessuna mano in mano e ci saranno momenti frustranti, ma fa tutto parte della maturazione come sviluppatore.
Nelle seguenti sottosezioni, spiegheremo ciascuno dei tipi di metodo e mostreremo anche l'implementazione dei metodi appartenenti a quella categoria. I nomi dei metodi sono abbastanza autoesplicativi riguardo al loro scopo, così come la loro implementazione, che riteniamo sia abbastanza facile da seguire. Tuttavia, prima di ciò, ricorda lo schema generale dei metodi di scrittura nei file .vue :
<script> // import statements here export default { // name, components, props, etc. data() { return { // the data that is so crucial for the application is defined here. } }, methods: { // methods (objects whose values are functions) here. // bulk of dynamic stuff (the black magic part) is controlled from here. method_1: function(arg_1) { }, method_2: function(arg_1, arg_2) { }, method_3: function(arg_1) { }, ……. }, computed: { // computed properties here }, // other objects, as necessary } </script>
Metodi di utilità
I metodi di utilità, come suggerisce il nome, sono metodi scritti principalmente allo scopo di modularizzare il codice ripetitivo utilizzato per attività marginali. Vengono chiamati con altri metodi quando necessario. Di seguito sono riportati i metodi di utilità per App.vue :
convertToTitleCase: function(str) { str = str.toLowerCase().split(' '); for (var i = 0; i < str.length; i++) { str[i] = str[i].charAt(0).toUpperCase() + str[i].slice(1); } return str.join(' '); },
// To format the “possibility” (of weather) string obtained from the weather API formatPossibility: function(str) { str = str.toLowerCase().split('-'); for (var i = 0; i < str.length; i++) { str[i] = str[i].charAt(0).toUpperCase() + str[i].slice(1); } return str.join(' '); },
// To convert Unix timestamps according to our convenience unixToHuman: function(timezone, timestamp) { /* READ THIS BEFORE JUDGING & DEBUGGING For any location beyond the arctic circle and the antarctic circle, the goddamn weather api does not return certain keys/values in each of this.rawWeatherData.daily.data[some_array_index]. Due to this, console throws up an error. The code is correct, the problem is with the API. May be later on I will add some padding to tackle missing values. */ var moment = require('moment-timezone'); // for handling date & time var decipher = new Date(timestamp * 1000); var human = moment(decipher) .tz(timezone) .format('llll'); var timeArray = human.split(' '); var timeNumeral = timeArray[4]; var timeSuffix = timeArray[5]; var justTime = timeNumeral + ' ' + timeSuffix; var monthDateArray = human.split(','); var monthDate = monthDateArray[1].trim(); return { fullTime: human, onlyTime: justTime, onlyMonthDate: monthDate }; },
// To convert temperature from fahrenheit to celcius fahToCel: function(tempInFahrenheit) { var tempInCelcius = Math.round((5 / 9) * (tempInFahrenheit — 32)); return tempInCelcius; },
// To convert the air pressure reading from millibar to kilopascal milibarToKiloPascal: function(pressureInMilibar) { var pressureInKPA = pressureInMilibar * 0.1; return Math.round(pressureInKPA); },
// To convert distance readings from miles to kilometers mileToKilometer: function(miles) { var kilometer = miles * 1.60934; return Math.round(kilometer); },
Sebbene non l'abbiamo implementato, puoi estrarre i metodi di utilità dal file .vue e inserirlo in un file JavaScript separato. Tutto quello che devi fare è importare il file .js all'inizio della parte dello script nel file .vue e dovresti essere a posto. Tale approccio funziona davvero bene e mantiene il codice pulito, specialmente nelle grandi applicazioni in cui potresti usare molti metodi che sono meglio raggruppati insieme in base al loro scopo. Puoi applicare questo approccio a tutti i gruppi di metodi elencati in questo articolo e vedere l'effetto stesso. Tuttavia, ti suggeriamo di fare quell'esercizio dopo aver seguito il corso presentato qui, in modo da avere il quadro generale di tutte le parti che funzionano in completa sincronia e avere anche un pezzo di software funzionante a cui puoi fare riferimento, una volta qualcosa pause durante la sperimentazione.
Metodi orientati ad azioni/eventi
Questi metodi vengono generalmente eseguiti quando è necessario eseguire un'azione corrispondente a un evento. A seconda dei casi, l'evento potrebbe essere attivato da un'interazione dell'utente o a livello di codice. Nel file App.vue , questi metodi si trovano sotto i metodi di utilità.
detectEnterKeyPress: function() { var input = this.$refs.input; input.addEventListener('keyup', function(event) { event.preventDefault(); var enterKeyCode = 13; if (event.keyCode === enterKeyCode) { this.setHitEnterKeyTrue(); } }); },
locationEntered: function() { var input = this.$refs.input; if (input.value === '') { this.location = "New York"; } else { this.location = this.convertToTitleCase(input.value); } this.makeInputEmpty(); this.makeTempVarTodayEmpty(); },
Una cosa interessante in alcuni dei frammenti di codice sopra è l'uso di $ref . In parole povere, è il modo in cui Vue associa l'istruzione di codice che la contiene, al costrutto HTML che dovrebbe influenzare (per maggiori informazioni, leggi la guida ufficiale). Ad esempio, i metodi makeInputEmpty() e detectEnterKeyPress() influiscono sulla casella di input, perché nell'HTML della casella di input abbiamo menzionato il valore dell'attributo ref come input .
Metodi di acquisizione dati
Stiamo utilizzando le seguenti due API nel nostro progetto:
API del geocodificatore di Google Maps Questa API serve per ottenere le coordinate della posizione che l'utente cerca. Avrai bisogno di una chiave API per te, che puoi ottenere seguendo la documentazione nel collegamento fornito. Per ora, puoi utilizzare la chiave API utilizzata da FusionCharts, ma ti chiediamo di non abusarne e di ottenere una tua chiave. Ci riferiamo all'API JavaScript da index.html di questo progetto e utilizzeremo i costruttori da essa forniti per il nostro codice nel file App.vue .
L'API di Dark Sky Weather Questa API serve per ottenere i dati meteorologici corrispondenti alle coordinate. Tuttavia, non lo useremo direttamente; lo avvolgeremo in un URL che reindirizza tramite uno dei server di FusionCharts. Il motivo è che se invii una richiesta GET all'API da un'applicazione interamente client-end come la nostra, si verifica il frustrante errore CORS (maggiori informazioni qui e qui).
Nota importante : poiché abbiamo utilizzato Google Maps e le API Dark Sky, entrambe queste API hanno le proprie chiavi API che abbiamo condiviso con te in questo articolo.Questo ti aiuterà a concentrarti sugli sviluppi lato client piuttosto che sul mal di testa dell'implementazione del back-end.Tuttavia, ti consigliamo di creare le tue chiavi , perché le nostre chiavi API avranno dei limiti e se questi limiti superano non sarai in grado di provare l'applicazione da solo.
Per Google Maps, vai a questo articolo per ottenere la tua chiave API. Per Dark Sky API, visita https://darksky.net/dev per creare la tua chiave API e i rispettivi endpoint.
Tenendo presente il contesto, vediamo l'implementazione dei metodi di acquisizione dati per il nostro progetto.
getCoordinates: function() { this.locationEntered(); var loc = this.location; var coords; var geocoder = new google.maps.Geocoder(); return new Promise(function(resolve, reject) { geocoder.geocode({ address: loc }, function(results, status) { if (status == google.maps.GeocoderStatus.OK) { this.lat = results[0].geometry.location.lat(); this.long = results[0].geometry.location.lng(); this.full_location = results[0].formatted_address; coords = { lat: this.lat, long: this.long, full_location: this.full_location }; resolve(coords); } else { alert("Oops! Couldn't get data for the location"); } }); }); },
/* The coordinates that Google Maps Geocoder API returns are way too accurate for our requirements. We need to bring it into shape before passing the coordinates on to the weather API. Although this is a data processing method in its own right, we can't help mentioning it right now, because the data acquisition method for the weather API has dependency on the output of this method. */ setFormatCoordinates: async function() { var coordinates = await this.getCoordinates(); this.lat = coordinates.lat; this.long = coordinates.long; this.currentWeather.full_location = coordinates.full_location; // Remember to beautify lat for N/S if (coordinates.lat > 0) { this.currentWeather.formatted_lat = (Math.round(coordinates.lat * 10000) / 10000).toString() + '°N'; } else if (coordinates.lat < 0) { this.currentWeather.formatted_lat = (-1 * (Math.round(coordinates.lat * 10000) / 10000)).toString() + '°S'; } else { this.currentWeather.formatted_lat = ( Math.round(coordinates.lat * 10000) / 10000 ).toString(); } // Remember to beautify long for N/S if (coordinates.long > 0) { this.currentWeather.formatted_long = (Math.round(coordinates.long * 10000) / 10000).toString() + '°E'; } else if (coordinates.long < 0) { this.currentWeather.formatted_long = (-1 * (Math.round(coordinates.long * 10000) / 10000)).toString() + '°W'; } else { this.currentWeather.formatted_long = ( Math.round(coordinates.long * 10000) / 10000 ).toString(); } },
/* This method dynamically creates the the correct weather API query URL, based on the formatted latitude and longitude. The complete URL is then fed to the method querying for weather data. Notice that the base URL used in this method (without the coordinates) points towards a FusionCharts server — we must redirect our GET request to the weather API through a server to avoid the CORS error. */ fixWeatherApi: async function() { await this.setFormatCoordinates(); var weatherApi = 'https://csm.fusioncharts.com/files/assets/wb/wb-data.php?src=darksky&lat=' + this.lat + '&long=' + this.long; this.completeWeatherApi = weatherApi; },
fetchWeatherData: async function() { await this.fixWeatherApi(); var axios = require('axios'); // for handling weather api promise var weatherApiResponse = await axios.get(this.completeWeatherApi); if (weatherApiResponse.status === 200) { this.rawWeatherData = weatherApiResponse.data; } else { alert('Hmm... Seems like our weather experts are busy!'); } },
Through these methods, we have introduced the concept of async-await in our code. If you have been a JavaScript developer for some time now, you must be familiar with the callback hell, which is a direct consequence of the asynchronous way JavaScript is written. ES6 allows us to bypass the cumbersome nested callbacks, and our code becomes much cleaner if we write JavaScript in a synchronous way, using the async-await technique. However, there is a downside. It takes away the speed that asynchronous code gives us, especially for the portions of the code that deals with data being exchanged over the internet. Since this is not a mission-critical application with low latency requirements, and our primary aim is to learn stuff, the clean code is much more preferable over the slightly fast code.
Data Processing Methods
Now that we have the methods that will bring the data to us, we need to prepare the ground for properly receiving and processing the data. Safety nets must be cast, and there should be no spills — data is the new gold (OK, that might be an exaggeration in our context)! Enough with the fuss, let's get to the point.
Technically, the methods we implement in this section are aimed at getting the data out of the acquisition methods and the data objects in App.vue , and sometimes setting the data objects to certain values that suits the purpose.
getSetHourlyTempInfoToday: function() { var unixTime = this.rawWeatherData.currently.time; var timezone = this.getTimezone(); var todayMonthDate = this.unixToHuman(timezone, unixTime).onlyMonthDate; var hourlyData = this.getHourlyInfoToday(); for (var i = 0; i < hourlyData.length; i++) { var hourlyTimeAllTypes = this.unixToHuman(timezone, hourlyData[i].time); var hourlyOnlyTime = hourlyTimeAllTypes.onlyTime; var hourlyMonthDate = hourlyTimeAllTypes.onlyMonthDate; if (todayMonthDate === hourlyMonthDate) { var hourlyObject = { hour: '', temp: '' }; hourlyObject.hour = hourlyOnlyTime; hourlyObject.temp = this.fahToCel(hourlyData[i].temperature).toString(); this.tempVar.tempToday.push(hourlyObject); /* Since we are using array.push(), we are just adding elements at the end of the array. Thus, the array is not getting emptied first when a new location is entered. to solve this problem, a method this.makeTempVarTodayEmpty() has been created, and called from this.locationEntered(). */ } } /* To cover the edge case where the local time is between 10 — 12 PM, and therefore there are only two elements in the array this.tempVar.tempToday. We need to add the points for minimum temperature and maximum temperature so that the chart gets generated with atleast four points. */ if (this.tempVar.tempToday.length <= 2) { var minTempObject = { hour: this.currentWeather.todayHighLow.todayTempHighTime, temp: this.currentWeather.todayHighLow.todayTempHigh }; var maxTempObject = { hour: this.currentWeather.todayHighLow.todayTempLowTime, temp: this.currentWeather.todayHighLow.todayTempLow }; /* Typically, lowest temp are at dawn, highest temp is around mid day. Thus we can safely arrange like min, max, temp after 10 PM. */ // array.unshift() adds stuff at the beginning of the array. // the order will be: min, max, 10 PM, 11 PM. this.tempVar.tempToday.unshift(maxTempObject, minTempObject); } },
Con i metodi di utilità, acquisizione ed elaborazione fuori mano, ora ci resta il compito di orchestrare l'intera cosa. Lo facciamo creando metodi di incollaggio di alto livello, che essenzialmente chiamano i metodi scritti sopra in una sequenza particolare, in modo che l'intera operazione venga eseguita senza problemi.
// Top level for info section // Data in this.currentWeather organizeCurrentWeatherInfo: function() { // data in this.currentWeather /* Coordinates and location is covered (get & set) in: — this.getCoordinates() — this.setFormatCoordinates() There are lots of async-await involved there. So it's better to keep them there. */ this.getSetCurrentTime(); this.getSetCurrentTemp(); this.getSetTodayTempHighLowWithTime(); this.getSetSummary(); this.getSetPossibility(); },
// Top level for highlights organizeTodayHighlights: function() { // top level for highlights this.getSetUVIndex(); this.getSetVisibility(); this.getSetWindStatus(); },
// Top level organization and rendering organizeAllDetails: async function() { // top level organization await this.fetchWeatherData(); this.organizeCurrentWeatherInfo(); this.organizeTodayHighlights(); this.getSetHourlyTempInfoToday(); },
montato
Vue fornisce hook del ciclo di vita dell'istanza, proprietà che sono essenzialmente metodi e vengono attivate quando il ciclo di vita dell'istanza raggiunge quella fase. Ad esempio, create, mount, beforeUpdate, ecc., sono tutti hook del ciclo di vita molto utili che consentono al programmatore di controllare l'istanza a un livello molto più granulare di quanto sarebbe stato possibile altrimenti.
Nel codice di un componente Vue, questi hook del ciclo di vita sono implementati proprio come faresti per qualsiasi altro prop . Per esempio:
<template> </template> <script> // import statements export default { data() { return { // data objects here } }, methods: { // methods here }, mounted: function(){ // function body here }, } </script> <style> </style>
Forte di questa nuova comprensione, dai un'occhiata al codice qui sotto per il supporto mounted di App.vue :
Abbiamo coperto molto terreno in questa sezione e le ultime sezioni ti hanno fornito cose a pezzetti. Tuttavia, è importante disporre del codice completo e assemblato per App.vue (soggetto a ulteriori modifiche nelle sezioni successive). Eccolo:
<template> <div> <div class="container-fluid"> <div class="row"> <div class="col-md-3 col-sm-4 col-xs-12 sidebar"> <div> <input type="text" ref="input" placeholder="Location?" @keyup.enter="organizeAllDetails" > <button @click="organizeAllDetails"> <img src="./assets/Search.svg" width="24" height="24"> </button> </div> <div> <div class="wrapper-left"> <div> {{ currentWeather.temp }} <span>°C</span> </div> <div>{{ currentWeather.summary }}</div> <div class="temp-max-min"> <div class="max-desc"> <div> <i>▲</i> {{ currentWeather.todayHighLow.todayTempHigh }} <span>°C</span> </div> <div>at {{ currentWeather.todayHighLow.todayTempHighTime }}</div> </div> <div class="min-desc"> <div> <i>▼</i> {{ currentWeather.todayHighLow.todayTempLow }} <span>°C</span> </div> <div>at {{ currentWeather.todayHighLow.todayTempLowTime }}</div> </div> </div> </div> <div class="wrapper-right"> <div class="date-time-info"> <div> <img src="./assets/calendar.svg" width="20" height="20"> {{ currentWeather.time }} </div> </div> <div class="location-info"> <div> <img src="./assets/location.svg" width="10.83" height="15.83" > {{ currentWeather.full_location }} <div class="mt-1"> Lat: {{ currentWeather.formatted_lat }} <br> Long: {{ currentWeather.formatted_long }} </div> </div> </div> </div> </div> </div> <dashboard-content class="col-md-9 col-sm-8 col-xs-12 content" :highlights="highlights" :tempVar="tempVar" ></dashboard-content> </div> </div> </div> </template> <script> import Content from './components/Content.vue'; export default { name: 'app', props: [], components: { 'dashboard-content': Content }, data() { return { weatherDetails: false, location: '', // raw location from input lat: '', // raw latitude from google maps api response long: '', // raw longitude from google maps api response completeWeatherApi: '', // weather api string with lat and long rawWeatherData: '', // raw response from weather api currentWeather: { full_location: '', // for full address formatted_lat: '', // for N/S formatted_long: '', // for E/W time: '', temp: '', todayHighLow: { todayTempHigh: '', todayTempHighTime: '', todayTempLow: '', todayTempLowTime: '' }, summary: '', possibility: '' }, tempVar: { tempToday: [ // gets added dynamically by this.getSetHourlyTempInfoToday() ], }, highlights: { uvIndex: '', visibility: '', windStatus: { windSpeed: '', windDirection: '', derivedWindDirection: '' }, } }; }, methods: { // Some utility functions convertToTitleCase: function(str) { str = str.toLowerCase().split(' '); for (var i = 0; i < str.length; i++) { str[i] = str[i].charAt(0).toUpperCase() + str[i].slice(1); } return str.join(' '); }, formatPossibility: function(str) { str = str.toLowerCase().split('-'); for (var i = 0; i < str.length; i++) { str[i] = str[i].charAt(0).toUpperCase() + str[i].slice(1); } return str.join(' '); }, unixToHuman: function(timezone, timestamp) { /* READ THIS BEFORE JUDGING & DEBUGGING For any location beyond the arctic circle and the antarctic circle, the goddamn weather api does not return certain keys/values in each of this.rawWeatherData.daily.data[some_array_index]. Due to this, console throws up an error. The code is correct, the problem is with the API. May be later on I will add some padding to tackle missing values. */ var moment = require('moment-timezone'); // for handling date & time var decipher = new Date(timestamp * 1000); var human = moment(decipher) .tz(timezone) .format('llll'); var timeArray = human.split(' '); var timeNumeral = timeArray[4]; var timeSuffix = timeArray[5]; var justTime = timeNumeral + ' ' + timeSuffix; var monthDateArray = human.split(','); var monthDate = monthDateArray[1].trim(); return { fullTime: human, onlyTime: justTime, onlyMonthDate: monthDate }; }, fahToCel: function(tempInFahrenheit) { var tempInCelcius = Math.round((5 / 9) * (tempInFahrenheit — 32)); return tempInCelcius; }, milibarToKiloPascal: function(pressureInMilibar) { var pressureInKPA = pressureInMilibar * 0.1; return Math.round(pressureInKPA); }, mileToKilometer: function(miles) { var kilometer = miles * 1.60934; return Math.round(kilometer); }, deriveWindDir: function(windDir) { var wind_directions_array = [ { minVal: 0, maxVal: 30, direction: 'N' }, { minVal: 31, maxVal: 45, direction: 'NNE' }, { minVal: 46, maxVal: 75, direction: 'NE' }, { minVal: 76, maxVal: 90, direction: 'ENE' }, { minVal: 91, maxVal: 120, direction: 'E' }, { minVal: 121, maxVal: 135, direction: 'ESE' }, { minVal: 136, maxVal: 165, direction: 'SE' }, { minVal: 166, maxVal: 180, direction: 'SSE' }, { minVal: 181, maxVal: 210, direction: 'S' }, { minVal: 211, maxVal: 225, direction: 'SSW' }, { minVal: 226, maxVal: 255, direction: 'SW' }, { minVal: 256, maxVal: 270, direction: 'WSW' }, { minVal: 271, maxVal: 300, direction: 'W' }, { minVal: 301, maxVal: 315, direction: 'WNW' }, { minVal: 316, maxVal: 345, direction: 'NW' }, { minVal: 346, maxVal: 360, direction: 'NNW' } ]; var wind_direction = ''; for (var i = 0; i < wind_directions_array.length; i++) { if ( windDir >= wind_directions_array[i].minVal && windDir <= wind_directions_array[i].maxVal ) { wind_direction = wind_directions_array[i].direction; } } return wind_direction; }, // Some basic action oriented functions makeInputEmpty: function() { this.$refs.input.value = ''; }, makeTempVarTodayEmpty: function() { this.tempVar.tempToday = []; }, detectEnterKeyPress: function() { var input = this.$refs.input; input.addEventListener('keyup', function(event) { event.preventDefault(); var enterKeyCode = 13; if (event.keyCode === enterKeyCode) { this.setHitEnterKeyTrue(); } }); }, locationEntered: function() { var input = this.$refs.input; if (input.value === '') { this.location = "New York"; } else { this.location = this.convertToTitleCase(input.value); } this.makeInputEmpty(); this.makeTempVarTodayEmpty(); }, getCoordinates: function() { this.locationEntered(); var loc = this.location; var coords; var geocoder = new google.maps.Geocoder(); return new Promise(function(resolve, reject) { geocoder.geocode({ address: loc }, function(results, status) { if (status == google.maps.GeocoderStatus.OK) { this.lat = results[0].geometry.location.lat(); this.long = results[0].geometry.location.lng(); this.full_location = results[0].formatted_address; coords = { lat: this.lat, long: this.long, full_location: this.full_location }; resolve(coords); } else { alert("Oops! Couldn't get data for the location"); } }); }); }, // Some basic asynchronous functions setFormatCoordinates: async function() { var coordinates = await this.getCoordinates(); this.lat = coordinates.lat; this.long = coordinates.long; this.currentWeather.full_location = coordinates.full_location; // Remember to beautify lat for N/S if (coordinates.lat > 0) { this.currentWeather.formatted_lat = (Math.round(coordinates.lat * 10000) / 10000).toString() + '°N'; } else if (coordinates.lat < 0) { this.currentWeather.formatted_lat = (-1 * (Math.round(coordinates.lat * 10000) / 10000)).toString() + '°S'; } else { this.currentWeather.formatted_lat = ( Math.round(coordinates.lat * 10000) / 10000 ).toString(); } // Remember to beautify long for N/S if (coordinates.long > 0) { this.currentWeather.formatted_long = (Math.round(coordinates.long * 10000) / 10000).toString() + '°E'; } else if (coordinates.long < 0) { this.currentWeather.formatted_long = (-1 * (Math.round(coordinates.long * 10000) / 10000)).toString() + '°W'; } else { this.currentWeather.formatted_long = ( Math.round(coordinates.long * 10000) / 10000 ).toString(); } }, fixWeatherApi: async function() { await this.setFormatCoordinates(); var weatherApi = 'https://csm.fusioncharts.com/files/assets/wb/wb-data.php?src=darksky&lat=' + this.lat + '&long=' + this.long; this.completeWeatherApi = weatherApi; }, fetchWeatherData: async function() { await this.fixWeatherApi(); var axios = require('axios'); // for handling weather api promise var weatherApiResponse = await axios.get(this.completeWeatherApi); if (weatherApiResponse.status === 200) { this.rawWeatherData = weatherApiResponse.data; } else { alert('Hmm... Seems like our weather experts are busy!'); } }, // Get and set functions; often combined, because they are short // For basic info — left panel/sidebar getTimezone: function() { return this.rawWeatherData.timezone; }, getSetCurrentTime: function() { var currentTime = this.rawWeatherData.currently.time; var timezone = this.getTimezone(); this.currentWeather.time = this.unixToHuman( timezone, currentTime ).fullTime; }, getSetSummary: function() { var currentSummary = this.convertToTitleCase( this.rawWeatherData.currently.summary ); if (currentSummary.includes(' And')) { currentSummary = currentSummary.replace(' And', ','); } this.currentWeather.summary = currentSummary; }, getSetPossibility: function() { var possible = this.formatPossibility(this.rawWeatherData.daily.icon); if (possible.includes(' And')) { possible = possible.replace(' And', ','); } this.currentWeather.possibility = possible; }, getSetCurrentTemp: function() { var currentTemp = this.rawWeatherData.currently.temperature; this.currentWeather.temp = this.fahToCel(currentTemp); }, getTodayDetails: function() { return this.rawWeatherData.daily.data[0]; }, getSetTodayTempHighLowWithTime: function() { var timezone = this.getTimezone(); var todayDetails = this.getTodayDetails(); this.currentWeather.todayHighLow.todayTempHigh = this.fahToCel( todayDetails.temperatureMax ); this.currentWeather.todayHighLow.todayTempHighTime = this.unixToHuman( timezone, todayDetails.temperatureMaxTime ).onlyTime; this.currentWeather.todayHighLow.todayTempLow = this.fahToCel( todayDetails.temperatureMin ); this.currentWeather.todayHighLow.todayTempLowTime = this.unixToHuman( timezone, todayDetails.temperatureMinTime ).onlyTime; }, getHourlyInfoToday: function() { return this.rawWeatherData.hourly.data; }, getSetHourlyTempInfoToday: function() { var unixTime = this.rawWeatherData.currently.time; var timezone = this.getTimezone(); var todayMonthDate = this.unixToHuman(timezone, unixTime).onlyMonthDate; var hourlyData = this.getHourlyInfoToday(); for (var i = 0; i < hourlyData.length; i++) { var hourlyTimeAllTypes = this.unixToHuman(timezone, hourlyData[i].time); var hourlyOnlyTime = hourlyTimeAllTypes.onlyTime; var hourlyMonthDate = hourlyTimeAllTypes.onlyMonthDate; if (todayMonthDate === hourlyMonthDate) { var hourlyObject = { hour: '', temp: '' }; hourlyObject.hour = hourlyOnlyTime; hourlyObject.temp = this.fahToCel(hourlyData[i].temperature).toString(); this.tempVar.tempToday.push(hourlyObject); /* Since we are using array.push(), we are just adding elements at the end of the array. Thus, the array is not getting emptied first when a new location is entered. to solve this problem, a method this.makeTempVarTodayEmpty() has been created, and called from this.locationEntered(). */ } } /* To cover the edge case where the local time is between 10 — 12 PM, and therefore there are only two elements in the array this.tempVar.tempToday. We need to add the points for minimum temperature and maximum temperature so that the chart gets generated with atleast four points. */ if (this.tempVar.tempToday.length <= 2) { var minTempObject = { hour: this.currentWeather.todayHighLow.todayTempHighTime, temp: this.currentWeather.todayHighLow.todayTempHigh }; var maxTempObject = { hour: this.currentWeather.todayHighLow.todayTempLowTime, temp: this.currentWeather.todayHighLow.todayTempLow }; /* Typically, lowest temp are at dawn, highest temp is around mid day. Thus we can safely arrange like min, max, temp after 10 PM. */ // array.unshift() adds stuff at the beginning of the array. // the order will be: min, max, 10 PM, 11 PM. this.tempVar.tempToday.unshift(maxTempObject, minTempObject); } }, // For Today Highlights getSetUVIndex: function() { var uvIndex = this.rawWeatherData.currently.uvIndex; this.highlights.uvIndex = uvIndex; }, getSetVisibility: function() { var visibilityInMiles = this.rawWeatherData.currently.visibility; this.highlights.visibility = this.mileToKilometer(visibilityInMiles); }, getSetWindStatus: function() { var windSpeedInMiles = this.rawWeatherData.currently.windSpeed; this.highlights.windStatus.windSpeed = this.mileToKilometer( windSpeedInMiles ); var absoluteWindDir = this.rawWeatherData.currently.windBearing; this.highlights.windStatus.windDirection = absoluteWindDir; this.highlights.windStatus.derivedWindDirection = this.deriveWindDir( absoluteWindDir ); }, // top level for info section organizeCurrentWeatherInfo: function() { // data in this.currentWeather /* Coordinates and location is covered (get & set) in: — this.getCoordinates() — this.setFormatCoordinates() There are lots of async-await involved there. So it's better to keep them there. */ this.getSetCurrentTime(); this.getSetCurrentTemp(); this.getSetTodayTempHighLowWithTime(); this.getSetSummary(); this.getSetPossibility(); }, organizeTodayHighlights: function() { // top level for highlights this.getSetUVIndex(); this.getSetVisibility(); this.getSetWindStatus(); }, // topmost level orchestration organizeAllDetails: async function() { // top level organization await this.fetchWeatherData(); this.organizeCurrentWeatherInfo(); this.organizeTodayHighlights(); this.getSetHourlyTempInfoToday(); }, }, mounted: async function() { this.location = "New York"; await this.organizeAllDetails(); } }; </script>
E finalmente, dopo tanta pazienza e duro lavoro, puoi vedere il flusso di dati con la sua pura potenza! Visita l'applicazione sul browser, aggiorna la pagina, cerca una posizione nella casella di ricerca dell'applicazione e premi Invio !
(Grande anteprima)
Ora che abbiamo finito con tutto il lavoro pesante, prenditi una pausa. Le sezioni successive si concentrano sull'uso dei dati per creare grafici belli e informativi, seguiti dal dare alla nostra applicazione dall'aspetto brutto una meritata sessione di toelettatura utilizzando CSS.
5. Visualizzazione dei dati con FusionCharts
Considerazioni fondamentali per i grafici
Per l'utente finale, l'essenza di una dashboard è essenzialmente questa: una raccolta di informazioni filtrate e accuratamente curate su un particolare argomento, veicolate attraverso strumenti visivi/grafici per una rapida assunzione. A loro non interessano le sottigliezze della progettazione della pipeline di dati o l'estetica del codice: tutto ciò che vogliono è una vista di alto livello in 3 secondi. Pertanto, la nostra grezza applicazione che mostra i dati di testo non significa nulla per loro ed è giunto il momento di implementare meccanismi per avvolgere i dati con i grafici.
Tuttavia, prima di approfondire l'implementazione dei grafici, consideriamo alcune domande pertinenti e le possibili risposte dal nostro punto di vista:
Che tipo di grafici sono appropriati per il tipo di dati con cui abbiamo a che fare? Bene, la risposta ha due aspetti: il contesto e lo scopo. Per contesto, intendiamo il tipo di dati, ed è nel complesso adatto allo schema di cose più grandi, limitato dall'ambito e dal pubblico del progetto. E per scopo, intendiamo essenzialmente "su cosa vogliamo sottolineare?". Ad esempio, possiamo rappresentare la temperatura odierna in diversi momenti della giornata utilizzando un istogramma (colonne verticali di uguale larghezza, con altezza proporzionale al valore rappresentato dalla colonna). Tuttavia, raramente siamo interessati ai singoli valori, ma piuttosto alla variazione e alla tendenza complessive dei dati. Per soddisfare lo scopo, è nel nostro interesse utilizzare un grafico a linee e lo faremo a breve.
Cosa si dovrebbe tenere a mente prima di selezionare una libreria di grafici? Dal momento che stiamo realizzando un progetto utilizzando prevalentemente tecnologie basate su JavaScript, è un gioco da ragazzi che qualsiasi libreria di grafici che scegliamo per il nostro progetto dovrebbe essere nativa del mondo JavaScript. Con questa premessa di base in mente, dovremmo considerare quanto segue prima di azzerare qualsiasi libreria particolare:
Supporto per i framework di nostra scelta , che in questo caso è Vue.js. Un progetto può essere sviluppato in altri framework JavaScript popolari come React o Angular: controlla il supporto della libreria di grafici per il tuo framework preferito. Inoltre, deve essere preso in considerazione il supporto per altri linguaggi di programmazione popolari come Python, Java, C++, .Net (AS e VB), specialmente quando il progetto coinvolge alcune cose di back-end serie.
Disponibilità di tipi e caratteristiche di grafici , poiché è quasi impossibile sapere in anticipo quale sarà la forma finale e lo scopo dei dati nel progetto (soprattutto se i requisiti sono regolati dai tuoi clienti in un ambiente professionale). In questo caso, dovresti allargare la tua rete e scegliere una libreria di grafici che abbia la più ampia raccolta di grafici. Ancora più importante, per differenziare il tuo progetto dagli altri, la libreria dovrebbe avere funzionalità sufficienti sotto forma di attributi dei grafici configurabili, in modo da poter mettere a punto e personalizzare la maggior parte degli aspetti dei grafici e il giusto livello di granularità. Inoltre, le configurazioni predefinite dei grafici dovrebbero essere ragionevoli e la documentazione della libreria deve essere di prim'ordine, per ragioni ovvie per gli sviluppatori professionisti.
Anche la curva di apprendimento, la comunità di supporto e l'equilibrio devono essere presi in considerazione, soprattutto quando si è nuovi alla visualizzazione dei dati. A un'estremità dello spettro, hai strumenti proprietari come Tableau e Qlickview che costano una bomba, hanno una curva di apprendimento regolare, ma presentano anche così tante limitazioni in termini di personalizzazione, integrazione e distribuzione. Dall'altra parte c'è d3.js: vasto, gratuito (open source) e personalizzabile fino in fondo, ma devi pagare il prezzo di una curva di apprendimento molto ripida per essere in grado di fare qualcosa di produttivo con la libreria.
Ciò di cui hai bisogno è il punto debole: il giusto equilibrio tra produttività, copertura, personalizzazione, curva di apprendimento e, fuori rotta, costo.Ti invitiamo a dare un'occhiata a FusionCharts, la libreria di grafici JavaScript più completa e pronta per l'azienda al mondo per il Web e i dispositivi mobili, che utilizzeremo in questo progetto per la creazione di grafici.
Introduzione a FusionCharts
FusionCharts è utilizzato in tutto il mondo come libreria di grafici JavaScript di riferimento da milioni di sviluppatori sparsi in centinaia di paesi in tutto il mondo. Tecnicamente, è il più caricato e configurabile possibile, con il supporto per l'integrazione con quasi tutti i popolari stack tecnologici utilizzati per progetti basati sul Web. L'uso commerciale di FusionCharts richiede una licenza e devi pagare per la licenza a seconda del caso d'uso (contatta il reparto vendite se sei curioso). Tuttavia, stiamo usando FusionCharts in questi progetti solo per provare alcune cose, e quindi la versione senza licenza (viene fornita con una piccola filigrana nei grafici e alcune altre restrizioni). L'utilizzo della versione senza licenza va benissimo quando si provano i grafici e li si utilizza nei propri progetti non commerciali o personali. Se hai intenzione di distribuire l'applicazione commercialmente, assicurati di avere una licenza da FusionCharts.
Poiché si tratta di un progetto che coinvolge Vue.js, avremo bisogno di due moduli che devono essere installati, se non fatti prima:
Il modulo fusioncharts , perché contiene tutto il necessario per creare i grafici
Il modulo vue-fusioncharts , che è essenzialmente un wrapper per fusioncharts, in modo che possa essere utilizzato in un progetto Vue.js
Se non li hai installati in precedenza (come indicato nella terza sezione), installali eseguendo il seguente comando dalla directory principale del progetto:
npm install fusioncharts vue-fusioncharts --save
Quindi, assicurati che il file src/main.js del progetto abbia il codice seguente (menzionato anche nella sezione 3):
import Vue from 'vue'; import App from './App.vue'; import FusionCharts from 'fusioncharts'; import Charts from 'fusioncharts/fusioncharts.charts'; import Widgets from 'fusioncharts/fusioncharts.widgets'; import PowerCharts from 'fusioncharts/fusioncharts.powercharts'; import FusionTheme from 'fusioncharts/themes/fusioncharts.theme.fusion'; import VueFusionCharts from 'vue-fusioncharts'; Charts(FusionCharts); PowerCharts(FusionCharts); Widgets(FusionCharts); FusionTheme(FusionCharts); Vue.use(VueFusionCharts, FusionCharts); new Vue({ el: '#app', render: h => h(App) })
Forse la riga più critica nello snippet sopra è la seguente:
Vue.use(VueFusionCharts, FusionCharts)
Indica a Vue di usare il modulo vue-fusioncharts per dare un senso a molte cose nel progetto che apparentemente non sono definite esplicitamente da noi, ma sono definite nel modulo stesso. Inoltre, questo tipo di affermazione implica una dichiarazione globale , con la quale intendiamo che ovunque Vue incontri qualcosa di strano nel codice del nostro progetto (cose che non abbiamo definito esplicitamente sull'uso di FusionCharts), apparirà almeno una volta in vue-fusioncharts e fusioncharts node moduli per le loro definizioni, prima di generare errori. Se avessimo usato FusionCharts in una parte isolata del nostro progetto (non usandolo in quasi tutti i file dei componenti), forse la dichiarazione locale avrebbe avuto più senso.
Con ciò, sei pronto per utilizzare FusionCharts nel progetto. Utilizzeremo una discreta varietà di grafici, la scelta dipenderà dall'aspetto dei dati meteorologici che vogliamo visualizzare. Inoltre, vedremo l'interazione tra data binding, componenti personalizzati e osservatori in azione.
Schema generale per l'utilizzo di Fusioncharts nei file .vue
In questa sezione, spiegheremo l'idea generale di utilizzare FusionCharts per creare vari grafici nei file .vue . Ma prima, vediamo lo pseudocodice che illustra schematicamente l'idea centrale.
Comprendiamo diverse parti dello pseudocodice sopra:
Nel <template> , all'interno del livello superiore <div> (che è praticamente obbligatorio per il codice HTML del modello di ogni componente), abbiamo il componente personalizzato <fusioncharts> . Abbiamo la definizione del componente contenuta nel modulo vue-fusioncharts Node che abbiamo installato per questo progetto. Internamente, vue-fusioncharts si basa sul modulo fusioncharts , anch'esso installato. Abbiamo importato i moduli necessari e risolto le loro dipendenze, ordinato a Vue di utilizzare il wrapper globalmente (in tutto il progetto) nel file src/main.js , e quindi non manca la definizione per il componente personalizzato <fusioncharts> che abbiamo utilizzato qui. Inoltre, il componente personalizzato ha attributi personalizzati e ciascuno degli attributi personalizzati è associato a un oggetto dati (e, a sua volta, ai loro valori), dalla direttiva v-bind , per la quale l'abbreviazione è il simbolo dei due punti ( : ). Impareremo gli attributi e i loro oggetti dati associati in modo più dettagliato, quando discuteremo alcuni dei grafici specifici utilizzati in questo progetto.
Nello <script> , prima dichiari gli oggetti di scena che il componente dovrebbe ricevere, quindi continui a definire gli oggetti dati che sono limitati agli attributi di <fusioncharts> . I valori assegnati agli oggetti dati sono i valori che gli attributi di <fusioncharts> e i grafici vengono creati sulla base di quei valori inseriti. Oltre a questi, la parte più interessante del codice è l'oggetto watch { } . Questo è un oggetto molto speciale nello schema delle cose di Vue: essenzialmente indica a Vue di sorvegliare eventuali modifiche che accadono a determinati dati e quindi di intraprendere azioni in base a come è stata definita la funzione del handler per quei dati. Ad esempio, vogliamo che Vue tenga d'occhio il prop ricevuto, cioè data_prop_received_by_the_component nello pseudocodice. L'oggetto di prop diventa una chiave nell'oggetto watch { } e il valore della chiave è un altro oggetto: un metodo di gestione che descrive ciò che deve essere fatto ogni volta che l'oggetto di prop cambia. Con meccanismi così eleganti per gestire le modifiche, l'app mantiene la sua reattività. Il deep: true rappresenta un flag booleano che puoi associare agli osservatori, in modo che l'oggetto osservato sia osservato in modo piuttosto profondo, ovvero anche le modifiche apportate ai livelli nidificati dell'oggetto vengano tracciate. ( Per maggiori informazioni sugli osservatori, consultare la documentazione ufficiale ).
Ora che sei dotato di una comprensione dello schema generale delle cose, immergiamoci nelle implementazioni specifiche dei grafici nei file dei componenti .vue . Il codice sarà abbastanza autoesplicativo e dovresti cercare di capire come le specifiche si adattano allo schema generale delle cose sopra descritte.
Implementazione di grafici in file .vue
Sebbene le specifiche stesse dell'implementazione varino da un grafico all'altro, la seguente spiegazione è applicabile a tutti loro:
<template> Come spiegato in precedenza, il componente personalizzato <fusioncharts> ha diversi attributi, ciascuno dei quali è associato all'oggetto dati corrispondente definito nella funzione data() utilizzando la direttiva v-bind :. I nomi degli attributi sono abbastanza autoesplicativi per il loro significato e anche capire gli oggetti dati corrispondenti è banale.
<script> Nella funzione data() , gli oggetti dati e i loro valori sono ciò che fa funzionare i grafici, a causa del collegamento eseguito dalle direttive v-bind ( : ) utilizzate sugli attributi di <fusioncharts> . Prima di approfondire i singoli oggetti dati, vale la pena menzionare alcune caratteristiche generali:
Gli oggetti dati i cui valori sono 0 o 1 sono di natura booleana, dove 0 rappresenta qualcosa non disponibile/disattivato e 1 rappresenta lo stato di disponibilità/attivato. Tuttavia, fai attenzione che gli oggetti dati non booleani possono anche avere 0 o 1 come valori, oltre ad altri possibili valori: dipende dal contesto. Ad esempio, containerbackgroundopacity con il valore predefinito 0 è booleano, mentre lowerLimit con il valore predefinito 0 significa semplicemente che il numero zero è il suo valore letterale.
Alcuni oggetti dati si occupano di proprietà CSS come margine, riempimento, dimensione del carattere, ecc. — il valore ha un'unità implicita di "px" o pixel. Allo stesso modo, altri oggetti dati possono avere unità implicite associate ai loro valori. Per informazioni dettagliate, fare riferimento alla rispettiva pagina degli attributi dei grafici di FusionCharts Dev Center.
Nella funzione data() , forse l'oggetto più interessante e non ovvio è dataSource. Questo oggetto ha tre oggetti principali nidificati al suo interno:
grafico : questo oggetto incapsula molti attributi del grafico relativi alla configurazione e ai cosmetici del grafico. È quasi un costrutto obbligatorio che troverai in tutti i grafici che creerai per questo progetto.
colorrange : questo oggetto è in qualche modo specifico del grafico in esame ed è presente principalmente nei grafici che si occupano di più colori/sfumature per delimitare diversi sotto-intervalli della scala utilizzata nel grafico.
valore: Questo oggetto, ancora, è presente nei grafici che ha un valore specifico che deve essere evidenziato nell'intervallo della scala.
L'oggetto watch { } è forse la cosa più cruciale che dà vita a questo grafico e agli altri grafici utilizzati in questo progetto. La reattività dei grafici, ovvero i grafici che si aggiornano in base ai nuovi valori risultanti da una nuova query dell'utente, è controllata dai watcher definiti in questo oggetto. Ad esempio, abbiamo definito un osservatore per i highlights dell'elica ricevuti dal componente, quindi abbiamo definito una funzione di gestione per istruire Vue sulle azioni necessarie da intraprendere, quando qualcosa cambia nell'oggetto osservato nell'intero progetto. Ciò significa che ogni volta che App.vue restituisce un nuovo valore per uno qualsiasi degli oggetti all'interno di highlights , le informazioni scendono fino a questo componente e il nuovo valore viene aggiornato negli oggetti dati di questo componente. Anche il grafico associato ai valori viene aggiornato come risultato di questo meccanismo.
Le spiegazioni di cui sopra sono tratti piuttosto ampi per aiutarci a sviluppare una comprensione intuitiva del quadro più ampio. Una volta compresi i concetti in modo intuitivo, puoi sempre consultare la documentazione di Vue.js e FusionCharts, quando qualcosa non ti è chiaro dal codice stesso. Lasciamo l'esercizio a te, e dalla prossima sottosezione in poi, non spiegheremo le cose che abbiamo trattato in questa sottosezione.
Questo componente contiene un grafico estremamente utile: il misuratore angolare.
(Grande anteprima)
Il codice per il componente è riportato di seguito. Per informazioni dettagliate sugli attributi del grafico di Angular Gauge, fare riferimento alla pagina FusionCharts Dev Center per Angular Gauge.
In questo componente, utilizziamo un misuratore lineare orizzontale per rappresentare la visibilità, come mostrato nell'immagine seguente:
(Grande anteprima)
Il codice per il componente è riportato di seguito. Per una comprensione approfondita dei diversi attributi di questo tipo di grafico, fare riferimento alla pagina FusionCharts Dev Center per il misuratore lineare orizzontale.
Questo componente mostra la velocità e la direzione del vento (velocità del vento, se sei esperto di fisica) ed è molto difficile rappresentare un vettore usando un grafico. In questi casi, suggeriamo di rappresentarli con l'ausilio di alcune belle immagini e valori di testo. Poiché la rappresentazione a cui abbiamo pensato dipende interamente dai CSS, la implementeremo nella prossima sezione che si occupa dei CSS. Tuttavia, dai un'occhiata a ciò che miriamo a creare:
Ricordiamo che abbiamo già implementato il codice con CSS per tutti i componenti, ad eccezione di Content.vue e Highlights.vue . Poiché Content.vue è un componente stupido che trasmette semplicemente i dati, lo stile minimo di cui ha bisogno è già stato coperto. Inoltre, abbiamo già scritto un codice appropriato per lo stile della barra laterale e delle carte contenenti i grafici. Pertanto, tutto ciò che ci resta da fare è aggiungere alcuni bit stilistici a Highlights.vue , che prevede principalmente l'utilizzo delle classi CSS:
Con le classifiche e lo stile in ordine, abbiamo finito! Prenditi un momento per apprezzare la bellezza della tua creazione.
(Grande anteprima)
Ora è il momento di distribuire la tua applicazione e condividerla con i tuoi colleghi. Se non hai molte idee sull'implementazione e ti aspetti che ti aiutiamo, dai un'occhiata qui alle nostre idee sull'implementazione. L'articolo collegato contiene anche suggerimenti su come rimuovere la filigrana FusionCharts nella parte inferiore sinistra di ogni grafico.
Se sbagli da qualche parte e vuoi un punto di riferimento, il codice sorgente è disponibile su Github.