Guida tutorial a Vue.js – 5° parte – applicazioni a singola pagina

In questa 5° puntata della guida Vue.js esamineremo l’installazione di Vue attraverso Vue-cli, analizzeremo i cd. “single file components” e realizzeremo un’applicazione a singola pagina dedicata agli annunci immobiliari.

Al termine dell’articolo precedente siamo arrivati a costruire un’elementare pagina web di annunci immobiliari grazie all’uso dei componenti di Vue.js. In questo articolo realizzeremo lo stessa pagina web con l’ausilio dei componenti su singolo file. Se non ti troverai a lavorare soltanto su progetti di piccole dimensioni, i c.d. single file components diventeranno la normalità nel tuo flusso di lavoro. Invece di inserire il codice html e gli script di Vue.js in un unico file, come abbiamo fatto fino ad ora, i progetti più impegnativi verranno separati in diversi file, ognuno relativo ad un componente, che verranno assemblati alla fine in un unico file grazie ad un module bundler.
I vantaggi di questo tipo di workflow sono diversi:

  • Normale utilizzo di codice html. Come abbiamo visto nell’articolo precedente di questa guida a Vue.js il codice html del template dei singoli componenti veniva inserito all’interno di codice javascript. Il risultato è che l’evidenziazione del codice html non poteva essere eseguita dal tuo editor, ed alla fine di ogni riga dovevi inserire il fastidioso simbolo \ per evitare errori nell’output. Con i singoli file il codice è realmente html, e potrai scriverlo come sei abituato a fare;
  • Supporto ad EcmaScript 6. Potrai utilizzare la nuova sintassi javascript senza preoccuparti della retrocompatibilità del codice, perchè nel momento in cui i file verranno compilati in un unico file, il codice javascript verrà elaborato in modo da essere utilizzabile anche dai browser più datati;
  • CSS specifici per singolo componente. All’interno del singolo file del componente, è possibile inserire delle istruzioni css che verranno applicate soltanto a quel componente.

Come ho detto nel primo articolo della guida, Vue.js non richiede di per sè complicate procedure di installazione, è sufficiente aggiungere lo script che lo richiama nella head del documento ed il gioco è fatto. Tuttavia, man mano che l’applicazione aumenta di complessità, si rende necessaria l’installazione attraverso un module bundler, che nel nostro caso è Webpack. Per rendere le cose più facili useremo un utilissimo tool chiamato vue-cli (cli sta per command line interface), che si occuperà di tutto il lavoro sporco. Prima di procedere devi avere installato sul tuo computer node.js.

Installiamo Vue.js con Vue-Cli

Apri la console dei comandi (su Windows io uso Powershell) e digita:

npm install -g @vue/cli

Così avrai installato vue-cli globalmente nella tua macchina e non in una cartella specifica. Nel momento in cui scrivo vue-cli è arrivato alla versione 3.2, per cui i passaggi che seguono si riferiscono a tale versione.
Raggiungi la cartella che dovrà contenere il tuo progetto e digita

vue create mioprogetto

ovviamente al posto di mioprogetto puoi utilizzare il nome che preferisci. A questo punto ti verrà chiesto di scegliere tra l’installazione predefinita e quella manuale. Scegli la seconda, così potrai selezionare le librerie da inserire nel progetto. Nel nostro caso possiamo limitarci a tre plugin: Babel, Router, Linter, come nella schermata che segue.
schermata di installazione vue-cli
Rispondi no alla richiesta di utilizzare la modalità history e alla domanda successiva seleziona ESLint + Standard config poi Lint on Save e poi package.json. Alla fine rispondi no alla richiesta di salvare la configurazione come predefinita. Forse siamo andati un po’ troppo veloci, ma tutte le opzioni che abbiamo visto richiederebbero un articolo a parte e non sono fondamentali per la comprensione del nostro tutorial.
All’interno della directory di partenza troverai una nuova cartella con lo stesso nome del progetto che hai appena creato. A questo punto accedi alla nuova directory digitando

cd mioprogetto

dopodichè puoi digitare

npm install

ed alla fine digita

npm run serve

Se tutto è andato come previsto, sul tuo browser predefinito dovrebbe aprirsi una pagina all’indirizzo http://localhost:8080/#/con questo contenuto:
schermata iniziale del progetto vue.js

In ogni caso, la console dei comandi ti indicherà l’url locale dove gira il progetto.

Link in affiliazione

Cerchiamo di capire cosa è successo. Nella directory di installazione dovresti trovare una cartella denominata “mioprogetto” (o qualsiasi altro nome tu abbia scelto durante il procedimento di installazione visto sopra). All’interno di questa cartella troverai, tra l’altro, tre sottocartelle:

  • node_modules: questa cartella contiene le librerie necessarie alla nostra applicazione;
  • public: questa cartella contiene i file che non devono essere elaborati da Webpack nella creazione dell’applicazione. In questo momento dovresti trovarci i file favicon.ico ed index.html;
  • src: la cartella più importante per i nostri scopi, contiene le sottocartelle assets, components e views, nonchè i file App.vue, main.js e router.jsche esamineremo di seguito.

In questo momento il progetto gira in modalità sviluppo, torna alla console dei comandi e digita

npm run build

In questo modo Webpack compilerà i file destinati alla produzione e li posizionerà all’interno di una nuova cartella denominata dist. Terminato il processo puoi digitare nuovamente

npm run serve

Il contenuto delle directory del nostro progetto Vue.js

La cartella assets è destinata a contenere i file che devono essere elaborati ed ottimizzati da Webpack nel processo di compilazione, come ad esempio i file .css oppure i file contenenti i font usati nel progetto.
La cartella components, come puoi immaginare, contiene i file dei singoli componenti utilizzati nell’applicazione. In questo momento ce n’è solo uno HelloWorld.vue.
La cartella views contiene i file delle singole pagine dell’applicazione, in questo momento trovi i file Home.vue e About.vue. A riprova di ciò, se torni nella videata del browser che abbiamo visto prima, noterai i link a due pagine, la pagina Home, sulla quale ti trovi già, e la pagina About.

Per orientarci tra file e cartelle e capire quello che sta accadendo, cominciamo ad esaminare il file index.html contenuto all’interno della cartella public, che dovrebbe avere questo contenuto:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>mioprogetto</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but provainstallazione doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

Nota la differenza con il file html che abbiamo utilizzato fino ad ora: non ci sono tag script ma soltanto un div contrassegnato dall’id app, all’interno del quale verrà assemblata l’app creata con Vue.
Per capire meglio questo passaggio apri il file main.js, che ha il seguente contenuto

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

Esaminiamo le istruzioni contenute all’interno del file:

import Vue from 'vue'

con questa istruzione importiamo il modulo Vue presente all’interno della cartella node_modules;

import App from './App.vue'

Con questa istruzione importiamo il componente principale di tutta l’applicazione, contenuto nel file App.vue, con tutto quello che è presente al suo interno;

import router from './router'

Quando abbiamo installato il progetto, abbiamo selezionato ‘router’ tra i tool disponibili. Così facendo, abbiamo incluso nell’installazione il plugin Vue-router, che ci consente di eseguire il routing all’interno della nostra applicazione.

Il routing è il sistema che ci consente di passare da un url ad un altro all’interno della stessa applicazione senza che venga ricaricata l’intera pagina. Grazie a Vue Router potremo prevedere diversi url, ognuno contrassegnato da uno specifico percorso, al quale abbineremo un determinato componente. Lo vedremo meglio più avanti nell’articolo.
Alla fine del file troviamo l’istruzione più importante, con la quale viene creata una nuova istanza di Vue, alla quale diciamo di utilizzare il router, di eseguire il render del componente App

render: h => h(App)

e di visualizzare il rendering all’interno del div#app

.$mount('#app')

Ricapitoliamo quanto detto fino ad ora: Abbiamo un file index.html che contiene un div contrassegnato dall’id app. Abbiamo anche un file main.js che crea un’istanza Vue (con tutti i suoi componenti) e la renderizza all’interno del div #app. Vediamo ora qual è il contenuto di questo rendering, per farlo dobbiamo aprire il file del componente principale dell’applicazione, cioè il file App.vue.

Il file App.vue

Come ho già detto il file App.vue rappresenta il componente principale dell’applicazione, e per default si presenta con il codice che segue:

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </div>
    <router-view/>
  </div>
</template>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
#nav {
  padding: 30px;
}

#nav a {
  font-weight: bold;
  color: #2c3e50;
}

#nav a.router-link-exact-active {
  color: #42b983;
}
</style>

Come puoi notare, il codice html da utilizzare all’interno del componente va inserito all’interno del tag template e non necessita di alcun simbolo \ alla fine di ciascuna riga. Il codice infatti viene scritto come normale html e non all’interno di uno script javascript come abbiamo fatto nell’articolo precedente. Ci sono però alcuni tag tipici di Vue-Router, che poco hanno a che fare con il linguaggio html tradizionale. Mi riferisco ovviamente ai componenti router-link e router-view. Il primo è il componente che viene utilizzato per navigare tra i vari indirizzi url all’interno della stessa applicazione Vue, un po’ come il normale tag a, solo che invece dell’attributo href utilizziamo to= seguito dalla route che desideriamo. Il secondo componente è router-view, che si utilizza per individuare il punto dove renderizzare il componente abbinato a quella vista.
Ma cosa sono queste routes? Capiamolo subito esaminando il file ruoter.js

Il file router.js

Al momento il contenuto del file è il seguente:

import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (about.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
    }
  ]
})

Anche questo file inizia con l’importazione di Vue e Vue router, dice inoltre a Vue di utilizzare il router

Vue.use(Router)

ma sopratutto crea un’istanza dell’oggetto Router che contiene le opzioni routes. Queste non sono altro che oggetti contenenti una serie di coppie chiave/valore, ciascuno dei quali assegna un componente ad una route. Esaminiamo il primo oggetto:

  • path: ‘/’ è l’url che contraddistingue questa route;
  • name: ‘home’ è il nome della route;
  • component: Home è il componente che verrà renderizzato quando il browser si troverà sull’url corrispondente al path.

In altre parole, ogni volta che il browser si troverà sull’url principale dell’applicazione, che nel nostro esempio sarà http://localhost:8080/, Vue renderizzerà il componente home. Quando si sposterà all’indirizzo http://localhost:8080/about, Vue renderizzerà il componente about.
Per capirci meglio apriamo il file home.vue che si trova all’interno della sottocartella views. Il suo contenuto dovrebbe essere il seguente:

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'home',
  components: {
    HelloWorld
  }
}
</script>

Esaminiamo il codice: abbiamo un tag template ed un tag script, che costituiscono la struttura tipica di un componente su singolo file. Il template ha all’interno un div che contiene un’immagine img ed un ulteriore componente denominato HelloWorld. E sì, perchè i componenti possono a loro volta contenere altri componenti (così come il componente principale dell’applicazione App.vue contiene tutti gli altri al suo interno). Per fare questo, dobbiamo andare al tag script ed inserire l’istruzione

import HelloWorld from '@/components/HelloWorld.vue'

con la quale diciamo a Vue di importare il componente dalla directory src (il simbolo @ indica tale cartella). Grazie all’importazione del componente, questo può essere usato all’interno del template, in caso contrario la pagina restituirebbe l’errore “HelloWorld is not defined”.
All’interno del tag script abbiamo anche un’istruzione export che esporta l’oggetto che definisce il nostro componente home. In particolare stabiliamo che il componente ha un nome, in questo caso home, ed un componente al suo interno, cioè HelloWorld. È possibile inserire altre caratteristiche, come le props ed i methods.
A questo punto non ci resta che aprire il componente HelloWorld, contenuto all’interno della directory components. Anche qui abbiamo un tag template, con all’interno il codice html da renderizzare nella pagina, ed un tag script che esporta l’oggetto che definisce il componente HelloWorld.

Per avere un’idea completa di quello che accade nelle applicazioni Vue, puoi scaricare un’estensione di Google Chrome che si chiama Vue.js devtools. Dopo averlo installato, troverai il logo di Vue a destra della barra degli indirizzi di Chrome, logo che diventerà verde ogni volta che il browser si troverà su una pagina web che funziona con Vue.js. Inoltre, aprendo gli “strumenti per sviluppatori”, o “developers tools”, troveremo una nuova tab Vue che ci evidenzia i dati dell’istanza Vue, come nell’immagine che segue:
schermata di avvio di Vue con i Vue devtools attivati
Come puoi notare dall’immagine, oppure aprendo la pagina di avvio del nostro progetto ed attivando la tab Vue, la pagina contiene un componente denominato App, con al suo interno un componente Home, che a sua volta contiene un componente HelloWorld.
Ora che abbiamo visto come funzionano i componenti su singolo file, possiamo procedere con la trasformazione del nostro sito di annunci immobiliari in una c.d. “Single Page Application”, o spa.

Un’applicazione a singola pagina con Vue.js

Visto che in questo articolo c’è già abbastanza carne al fuoco, in questa parte di tutorial non utilizzeremo il componente selezione-annunci, perciò nella pagina web verranno mostrati tutti gli annunci, senza distinguere tra “affitti” e “vendite”. Inoltre, inseriremo un nuovo componente relativo al singolo annuncio; sarà così possibile cliccare su ogni annuncio della lista per vedere il dettaglio di ciascuno, ovviamente senza dovere ricaricare la pagina web.
Iniziamo subito modificando il file index.html che si trova all’interno della cartella public. Devi eseguire alcuni passeggi:

  • Copia l’intero contenuto del file utilizzato fino alla fine del precedente articolo;
  • Incollalo all’interno del file index.html, al posto del codice attuale;
  • Cancella il codice contenuto all’interno del tag script, che riporteremo all’interno dei file dei componenti, con le opportune modifiche;
  • Cancella il contenuto della section id=”main-app” e rinomina l’id da main-app a app.
  • Torna nella cartella di lavoro che hai usato nelle parti precedenti di questa guida Vue.js, copia i file style.css e foundation.min.css incollali all’interno della cartella public;
  • All’interno del tag head cancella il seguente script:
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    

    , dopodichè modifica l’attributo href dei link ai file css che hai copiato aggiungendo il codice < %= BASE_URL % > subito prima del nome del file.

A questo punto il file index.html dovrebbe avere il contenuto che segue:

 
<!DOCTYPE html>
</html>
  <head>
    <title>Vue Tutorial</title>
      <link rel="stylesheet" href="<%= BASE_URL %>foundation.min.css">
      <link href="https://fonts.googleapis.com/css?family=Open+Sans|Oswald:700" rel="stylesheet">
      <link rel="stylesheet" href="<%= BASE_URL %>style.css">
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  </head>
  <body>
    <div class="wrapper row">
      <header class="site-header">
        <div class="site-branding small-12 large-3 columns" id="site-branding">
          <a href="/" title="Vue Tutorial">
              <h1 class="site-title">Vue Tutorial</h1>
          </a>
          <p class="site-description">Il sito per creare con Vue.js</p>
        </div><!-- .site-branding -->
        <div class="site-header-menu small-12 large-9 columns">
          <nav class="main-navigation" role="navigation" aria-label="Primary Menu">
            <ul id="menu-primary" class="menu">
              <li class="menu-item">
                <a href="#">Home</a>
              </li>
              <li class="menu-item">
                <a href="#">Chi siamo</a>
              </li>
              <li class="menu-item">
                <a href="#">Blog</a>
              </li>
              <li class="menu-item">
                <a href="#">Contatti</a>
              </li>
            </ul>
          </nav><!-- .main-navigation -->
        </div><!-- .site-header-menu -->
      </header>
    <section id="app"></section>
    <footer class="site-footer">
        <ul>
            <li><h3>Contatti</h3></li>
            <li>Facebook</li>
            <li>LinkedIn</li>
            <li>Google+</li>
        </ul>
    </footer>
  </body>
</html>

Adesso possiamo passare al componente fondamentaleApp, contenuto all’interno del file App.vue. Abbiamo già detto, ed è bene ribadirlo, che i componenti su singolo file contengono un tag template che racchiude il codice html ed un tag script in cui viene esportato un oggetto componente con le relative proprietà. È proprio quello che faremo adesso: apri il file App.vue e sostituisci il codice contenuto all’interno del tag template con il codice seguente

<div id="main-app">
  <router-view></router-view>
</div>

Dopo la chiusura del tag template troverai un tag style contenente alcuni stili css per noi inutili, cancellalo e inserisci il seguente codice:

<script>
export default {
  name: 'app',
  data() {
    return {
      gliAnnunci: []
    };
  },
  created: function() {
    $.getJSON('https://www.alessandrocosta.pro/wp-json/wp/v2/annunci')
      .done(data => {this.gliAnnunci = data;});
  }
}
</script>

Come abbiamo visto prima, l’istruzione export ci consente di esportare l’oggetto che definisce il componente. L’oggetto ha un nome, app ed una funzione data che restituisce i dati da visualizzare all’interno della vista, cioè gli annunci in formato json. Al contrario di quanto abbiamo fatto finora, questi dati non sono memorizzati all’interno di una variabile, ma vengono ricavati da un file json esterno da richiamare tramite ajax e memorizzati all’interno dell’array gliAnnunci.
Andiamo con ordine: inizialmente gliAnnunci è un array vuoto, per trasferire al suo interno i dati che ci interessano dobbiamo usare la funzione created. Si tratta di una funzione che viene chiamata automaticamente durante il ciclo di vita dell’istanza Vue, in particolare subito dopo che l’istanza è stata creata ma prima che sia renderizzata sullo schermo. In questa fase effettuiamo una chiamata ajax

$.getJSON('https://www.alessandrocosta.pro/wp-json/wp/v2/annunci')

al termine della quale assegniamo i dati json che abbiamo ottenuto all’array gliAnnunci

.done(data => {this.gliAnnunci = data;});

Adesso che abbiamo recuperato i dati json, li possiamo trasferiamo al template grazie alla direttiva v-bind. Modifica il tag router-view nel modo seguente:

<router-view :immobili="gliAnnunci" title="Immobili in affitto e vendita"></router-view>

Grazie alla direttiva v-bind, che abbiamo utilizzato nella forma abbreviata con i due punti, possiamo associare il contenuto di gliAnnunci alla proprietà immobili. Tale proprietà, fino alla scorso articolo, era propria del componente elenco-annunci. In questa trasposizione da singolo file a spa, diventa una proprietà del componente home. Apriamo quindi il file Home.vue all’interno della cartella views e sostituiamo il codice presente all’interno del tag template con il codice seguente:

<div class="product-list">
  <h2>{{title}}</h2>
  <ul>
    <elemento-lista-annunci v-for="(annuncio, i) in immobili" :annuncio="annuncio" :key="annuncio.id">
    </elemento-lista-annunci>
  </ul>
</div>

Esaminiamo le differenze con il componente elenco-annunci che abbiamo utilizzato nell’articolo precedente: in quel caso il componente conteneva il tag ul ed i tag li al suo interno. Nel nostro caso abbiamo racchiuso i tag li all’interno di un altro componente, denominato elemento-lista-annunci. Il ciclo v-for non viene quindi applicato al tag li ma al componente stesso.

All’interno del file inseriamo il tag script nel modo che segue:

<script>
import ElementoListaAnnunci from '@/components/ElementoListaAnnunci.vue';

export default {
  name: 'home',
  props: {
    immobili: {
      type: Array,
    },
    title: {
      type: String,
    }
  },
  components: {
    'elemento-lista-annunci': ElementoListaAnnunci
  }
}
</script>

Iniziamo con l’importare il componente ElementoListaAnnunci dal file ElementoListaAnnunci.vue, che ancora non esiste ma che creeremo fra poco. Dopodichè esportiamo l’oggetto che definisce il componente, al quale assegniamo il nome home, le props immobili e title. Dichiariamo anche il componente che utilizzeremo all’interno del template, che come abbiamo visto prima è elemento-lista-annunci. La props immobili è un array il cui contenuto corrisponde a quello dell’array gliAnnunci. Questo grazie alla direttiva v-bind utilizzata all’interno della router-view nel file App.vue.
Prima di passare al componente successivo, vorrei richiamare la tua attenzione sul tag elemento-lista-annunci che si trova all’interno del template, affinchè sia chiaro quello che succede. Ripeto il codice che abbiamo visto prima:

<elemento-lista-annunci v-for="(annuncio, i) in immobili" :annuncio="annuncio" :key="annuncio.id">
</elemento-lista-annunci>

Praticamente il componente elemento-lista-annunci viene ripetuto tante volte quanti sono gli elementi dell’array immobili, grazie alla direttiva v-for. Per ogni elemento dell’array immobili, elemento che chiameremo annuncio trasferiamo, attraverso la direttiva v-bind, il contenuto dell’elemento alla proprietà annuncio del componente elemento-lista-annunci.
Con il nostro editor, spostiamoci all’interno della cartella components e creiamo il file ElementoListaAnnunci.vue, che conterrà il codice che segue:

<template>
    <li class="small-12 large-4 columns">
        <img :src="annuncio.acf.immagine_1">
        <p>{{annuncio.title.rendered}}</p>
        <p>{{annuncio.acf.indirizzo}} - {{annuncio.acf.citta}}</p>
        <p>&euro; {{annuncio.acf.richiesta}} - $ {{Number(annuncio.acf.richiesta) * 1.22717}}</p>
    </li>
</template>

<script>
    export default {
        name: 'elemento-lista-annunci',
        props: {
            annuncio: {
                type: Object
            }
        },
    };
</script>

A questo punto il codice dovrebbe esserti familiare, il template contiene lo stesso codice html utilizzato all’interno del componente elenco-annunci utilizzato nello scorso capitolo della guida. Lo script come al solito contiene il nome del componente e la propannuncio, che è un oggetto contenente i dati dell’elemento dell’array immobili, trasferiti grazie alla direttiva v-bind.

A questo punto dovremmo trovarci di fronte ad un sito web simile a quello visto fino alla parte precedente della guida, con la differenza che il codice html è diviso in componenti nidificati, ognuno all’interno del proprio file, il suo apetto dovrebbe corrispondere alla schermata sottostante:
schermata principale della nostra app vue.js
Tanta fatica sembrerebbe sprecata se non facessimo l’ultimo passo, cioè creare un nuovo componente che visualizzi sullo schermo il singolo annuncio con tutti i suoi dettagli.

Spostiamoci tra le routes di Vue.js

Prima di scrivere il codice, mettiamo nero su bianco quali sono i passi da affrontare:

  • Dobbiamo creare un link che da ciascun annuncio della home page porti ad una nuova vista dedicata al singolo annuncio;
  • Dobbiamo creare una nuova route che punti ai singoli annunci;
  • Dobbiamo creare un nuovo componente, abbinato alla route del punto precedente, che visualizzi ciascun annuncio.

Iniziamo dal primo punto; per creare un link al singolo annuncio dobbiamo modificare il file ElementoListaAnnunci.vue. In particolare, aggiungiamo un link al paragrafo che visualizza il titolo dell’annuncio. Come già sai, in Vue.js i link non utilizzano il tag a bensì il tag router-link. Dobbiamo anche stabilire come impostare l’url al quale puntare. Considera che ogni annuncio ha un proprio id, l’ideale sarebbe impostare un l’url in modo tale da farlo terminare con l’id del singolo annuncio. Per renderti conto della cosa, ispeziona il primo annuncio attraverso il tab vue degli “strumenti per sviluppatori” di Google Chrome. Dovresti trovare una situazione come quella dell’immagine seguente:
il componente vue visto con gli strumenti per sviluppatori di Google Chrome
Come vedi, ogni annuncio ha un proprio id, e noi dobbiamo puntare ad un link che termini con questo numero. Pertanto modifica la seguente riga di codice del file ElementoListaAnnunci.vue da così:

<p>{{annuncio.title.rendered}}</p>

a così:

<p><router-link :to="'/' + annuncio.id">{{annuncio.title.rendered}}</router-link></p>

In pratica l’indirizzo a cui punterà il primo annuncio sarà http://localhost:8080/#/1875, il secondo punterà a http://localhost:8080/#/1876 e così via, in base all’id di ciascun annuncio. A proposito, se ti infastidisce il cancelletto all’interno dell’url, è possibile eliminarlo inserendo una nuova opzione all’interno dell’oggetto Router. Torna al file router.js e dopo la chiusura delle parentesi quadre dell’array routes inserisci una virgola ed a capo digita mode: ‘history’. In questa maniera verrà eliminato dall’url il cancelletto che abbiamo visto fino ad ora.
Andiamo al secondo punto della nostra lista, dobbiamo creare una nuova route, che punti all’id dell’annuncio ed al quale associare un nuovo componente.
Sempre nel file router.js aggiungi una nuovo path all’array routes, nel modo seguente:

routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/:id',
      component: AnnuncioImmobile
    }
  ]

Hai appena aggiunto un path caratterizzato da un segmento dinamico, infatti il valore dell’id è destinato a cambiare per ogni singolo annuncio. Per fare sì che la singola route possa puntare ad un indirizzo generato dinamicamente occorre inserire i due punti prima dell’id.
Assegniamo alla route un nuovo componente, che chiamiamo AnnuncioImmobile e si occuperà di visualizzare a schermo il singolo annuncio. Ricapitolando, il codice relativo all’oggetto Router del file router.js dovrebbe essere il seguente:

export default new Router({
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/:id',
      component: AnnuncioImmobile
    }
  ], 
  mode: 'history'
})

Non abbiamo ancora finito con questo file, è necessario infatti importare il componente AnnuncioImmobile, così come abbiamo fatto con il componente Home. Perciò vai alla riga n. 4 e scrivi il seguente codice:

import AnnuncioImmobile from './components/AnnuncioImmobile.vue'

A questo punto vai nella cartella components e crea un nuovo file AnnuncioImmobile.vue, ed inserisci al suo interno il codice seguente:

<template>
    <div>
        <router-link to="/">Indietro</router-link>
        <h2><strong >{{annuncioImmobile.title.rendered}}</strong></h2>
        <img :src="annuncioImmobile.acf.immagine_1">
        <p>Vani: {{annuncioImmobile.acf.vani}}</p>
        <p>Metri Quadri: {{annuncioImmobile.acf.mq}}</p>
        <p>Indirizzo: {{annuncioImmobile.acf.indirizzo}}</p>
        <p>Citt&agrave;: {{annuncioImmobile.acf.citta}}</p>
        <p>richiesta: € {{annuncioImmobile.acf.richiesta}}</p>
        <h3>Dettagli dell'immobile</h3>
        <p>{{annuncioImmobile.acf.descrizione}}</p>
    </div>
</template>

<script>
    export default {
        name: 'annuncio-immobile',
        data() {
            return {
                annuncioImmobile: {}
            }
        },
        created() {
            $.getJSON('https://www.alessandrocosta.pro/wp-json/wp/v2/annunci/' + this.$route.params.id)
                .done(data => {this.annuncioImmobile = data; ;})
        }
    };
</script>

<style scoped>
img {
    float: left;
    margin-right: 15px;
    width: 300px;
}

div {
    margin: 20px auto;
    width: 800px;
}
h3 {
    clear: both;
    padding-top: 20px;
}
</style>

All’interno del tag template, oltre ad un link alla route principale, cioè alla home, abbiamo una serie di paragrafi che riportano all’interno della sintassi a doppie parentesi graffe, i dati dell’oggetto annuncioImmobile. Questi dati sono quelli relativi al singolo annuncio e vengono ottenuti grazie ad una chiamata ajax, in modo simile a come abbiamo fatto nel file App.vue.
Attenzione quindi: la chiamata ajax ha un url diverso da quello utilizzato nel file App.vue; in quel caso il file json restituiva i dati di tutti gli annunci del sito, in questo caso vogliamo ottenere i dati del singolo annuncio. Come facciamo a formulare una chiamata che punti all’id dell’annuncio che ci interessa? Pensaci un attimo: dopo avere cliccato sull’annuncio visualizzato in home page, siamo stati indirizzati ad un url che ha al suo interno l’id dell’oggetto, per esempio 1875, e ci ritroviamo su una route che punta dinamicamente a quello stesso id. A questo punto l’istanza vue deve renderizzare all’interno di quella vista il componente annuncio-immobile; quali dati passare al componente? Quelli relativi all’annuncio con id uguale all’id della route. Per questo scriviamo la chiamata ajax così:

$.getJSON('https://www.alessandrocosta.pro/wp-json/wp/v2/annunci/' + this.$route.params.id)

dove this.$route.params.id restituisce l’id della route che abbiamo impostato dinamicamente poco sopra. Nel caso del primo annuncio, il codice equivale a

$.getJSON('https://www.alessandrocosta.pro/wp-json/wp/v2/annunci/' + 1875)

dove 1875 è esattamente il valore di this.$route.params.id.

Avrai notato il tag style scoped dopo la chiusura del tag script. Con l’attributo scoped facciamo in modo che gli stili inseriti all’interno di questo file si riferiscano esclusivamente al componente annuncio-immobile, e vengano caricati soltanto quando il componente viene renderizzato sullo schermo.

Salva tutti i file e vai sulla home page, se tutto è andato bene cliccando sul primo annuncio dovresti ottenere una pagina web così:
schermata del singolo annuncio della nostra single page application

Abbiamo terminato la nostra, seppur rudimentale, applicazione a singola pagina. Se questo articolo ti è stato utile condividilo cliccando sui pulsanti sotto!