Carosello immagini con Vue

Carosello immagini con Vue

In questa lezione svilupperemo un carosello di immagini con Vue. I caroselli di immagini sono componenti molto comuni nelle interfacce utente moderne. Con Vue.js, possiamo creare facilmente un carosello di immagini dinamico e reattivo che consentirà agli utenti di navigare attraverso diverse immagini in modo intuitivo.

Per seguire questo tutorial, è necessario avere una conoscenza di base di HTML, CSS e JavaScript, nonché una comprensione di base di Vue.js.

Impostazione del Progetto Carosello immagini con Vue

Innanzitutto creiamo un nuovo progetto Vue.js utilizzando Vue CLI:

vue create vue-carousel

Quindi seguiamo le istruzioni a schermo per la configurazione del progetto. Una volta creato il progetto, spostiamoci nella directory del progetto:

cd vue-carousel

Creazione del Componente Carosello con Vue

Ora creiamo il nostro componente carosello. All’interno della cartella src/components, creiamo un nuovo file chiamato CarouselComponent.vue e lavoriamo sul template, dove definiamo la struttura del caroselle in questo modo:

  • un contenitore principale carousel-container che racchiude l’intero carosello.
  • carousel è il contenitore degli elementi del carosello.
  • un altro contenitore carousel-inner che tiene le immagini e viene traslato per simulare lo scorrimento.
  • carousel-item rappresenta ciascun elemento dell’immagine nel carosello.
  • Gli attributi :style vengono utilizzati per applicare stili dinamici per la larghezza del carosello e per la trasformazione che muove le immagini.
  • Il ciclo v-for viene utilizzato per iterare attraverso l’array di immagini e renderizzarle dinamicamente.

Ecco di seguito la parte inerente il template:

<template>
  <div class="carousel-container" :style="{ width: carouselWidth + 'px' }">
    <h2>Carosello immagini</h2>
    <div class="carousel">
      <div class="carousel-inner" :style="{ transform: 'translateX(' + translateX + 'px)' }">
        <div v-for="(image, index) in images" :key="index" class="carousel-item">
          <img :src="image" alt="Carousel Image" />
        </div>
      </div>
    </div>
    <div class="carousel-controls">
      <button @click="prevSlide" :disabled="currentIndex === 0">Prev</button>
      <button @click="nextSlide" :disabled="currentIndex === totalItems - itemsPerPage">Next</button>
    </div>
  </div>
</template>

Continuiamo a lavorare con il carosello immagini con Vue, definendo la logica del componente nello script:

  • In data, definiamo lo stato iniziale del carosello, incluso l’indice corrente, la traslazione translateX, l’array di immagini e altre opzioni come il numero di immagini per pagina, la larghezza ed il margine di ciascuna immagine. Sostituite il valore 250 con la larghezza effettiva delle vostre immagini ed impostate anche il valore del margine desiderato.
  • Utilizziamo poi una proprietà computed carouselWidth per calcolare la larghezza totale del carosello in base alla larghezza dell’elemento e al margine tra di essi.
  • Definiamo i metodi nextSlide e prevSlide per gestire la navigazione avanti e indietro nel carosello.

Metodo nextSlide()

Questo metodo viene chiamato quando l’utente fa clic sul pulsante “Next” per scorrere avanti nel carosello.

  1. Prima di tutto, controlliamo se l’indice corrente currentIndex è inferiore al numero totale di elementi meno il numero di elementi visualizzati per pagina (totalItems - itemsPerPage). Questo controllo serve a garantire che non andremo oltre l’ultimo gruppo di immagini nel carosello.
  2. Se l’indice corrente è inferiore al valore massimo consentito, incrementiamo currentIndex di uno e spostiamo translateX verso sinistra. Questo viene fatto sottraendo dalla proprietà translateX la somma della larghezza di ciascuna immagine e del margine tra di esse (itemWidth + margin).

Metodo prevSlide()

Questo metodo viene dunque chiamato quando l’utente fa clic sul pulsante “Prev” per tornare indietro nel carosello.

  1. Prima di tutto, controlliamo se l’indice corrente currentIndex è maggiore di zero. Questo controllo serve a garantire che non andremo oltre la prima immagine nel carosello.
  2. Se l’indice corrente è maggiore di zero, decrementiamo currentIndex di uno e spostiamo translateX verso destra. Questo viene fatto aggiungendo alla proprietà translateX la somma della larghezza di ciascuna immagine e del margine tra di esse (itemWidth + margin).

In questo modo, ogni volta che l’utente preme i pulsanti “Next” o “Prev”, l’indice corrente viene aggiornato di conseguenza. Si aggiorna anche la proprietà translateX che determina la posizione del gruppo di immagini nel carosello, consentendo all’utente di scorrere tra le immagini in modo fluido.

Ecco dunque lo script:

<script>
export default {
  data() {
    return {
      currentIndex: 0,
      translateX: 0,
      images: [
        'https://cdn.pixabay.com/photo/2024/03/05/14/33/purple-8614655_640.jpg',
        'https://cdn.pixabay.com/photo/2023/01/10/16/23/hedgehog-7710053_640.jpg',
        'https://cdn.pixabay.com/photo/2022/11/07/18/29/bird-7576994_640.jpg',
        'https://cdn.pixabay.com/photo/2012/03/01/00/55/flowers-19830_960_720.jpg',
        'https://cdn.pixabay.com/photo/2024/02/15/15/29/crocus-8575610_640.jpg',
        'https://cdn.pixabay.com/photo/2015/04/10/01/41/fox-715588_960_720.jpg'
      ],
      itemsPerPage: 3, //sostituire con il numero di immagini desiderato
      itemWidth: 250, // Larghezza di ciascuna immagine
      margin: 20 // Margine delle immagini
    };
  },
  computed: {
    totalItems() {
      return this.images.length;
    },
    carouselWidth() {
      return (this.itemWidth + this.margin) * this.itemsPerPage;
    }
  },
  methods: {
    nextSlide() {
      if (this.currentIndex < this.totalItems - this.itemsPerPage) {
        this.currentIndex++;
        this.translateX -= this.itemWidth + this.margin;
      }
    },
    prevSlide() {
      if (this.currentIndex > 0) {
        this.currentIndex--;
        this.translateX += this.itemWidth + this.margin;
      }
    }
  }
};
</script>

Possiamo anche personalizzare lo stile del carosello aggiungendo regole CSS all’interno dello stile dello stesso componente:

<style scoped>
.carousel-container {
  margin: 0 auto;
  overflow: hidden;
}

.carousel {
  display: flex;
  margin-bottom: 10px;
}

.carousel-inner {
  display: flex;
  transition: transform 0.5s ease;
}

.carousel-item {
  flex: 0 0 auto;
}

.carousel img {
  width: 250px;
  height: auto;
  margin: 0 10px;
}

.carousel-controls {
  display: flex;
  justify-content: center;
}

.carousel-controls button {
  margin: 0 5px;
}
</style>

Conclusioni

In questo articolo, abbiamo esaminato come creare un carosello di immagini dinamico utilizzando Vue Abbiamo definito la struttura del nostro componente Vue, includendo elementi HTML per visualizzare le immagini e i controlli per navigare tra di esse.

Utilizzando il data binding di Vue, abbiamo anche collegato le immagini e le informazioni di navigazione al nostro componente, consentendo all’utente di scorrere avanti e indietro tra le immagini.

Abbiamo anche discusso l’importanza di calcolare dinamicamente la larghezza del carosello in base al numero di immagini e ai margini tra di esse, garantendo così che il carosello si adatti correttamente al contenuto e sia visualizzato correttamente su diversi dispositivi e dimensioni dello schermo.

Infine, abbiamo esaminato come personalizzare ulteriormente il carosello aggiungendo funzionalità come la navigazione automatica, gli indicatori di paginazione e altro ancora.

Dunque, con Vue.js è possibile creare facilmente caroselli di immagini interattivi e reattivi che migliorano l’esperienza utente sulle pagine web. Spero che questo articolo sia di aiuto a tanti aspiranti programmatori che desiderano creare progetti interattivi con Vue.js!

Alcuni link utili

Tutorial JavaScript

Componenti Vue.js

Option API

Composition API

Counter in Vue.js (con le due sintassi: Option API e Composition API)

Direttiva v-model

props con Option API

Watch in Vue.js

Watch in Vue.js

In questa lezione parliamo di watch in Vue.js. I watchers in Vue.js consentono di eseguire del codice quando i dati reattivi cambiano. A differenza delle computed properties, i watchers non calcolano un valore; piuttosto, eseguono del codice quando si verificano specifiche modifiche di dati. Si possono utilizzare i watchers per eseguire azioni asincrone, effettuare chiamate AJAX o eseguire altre operazioni quando i dati cambiano.

Esempio Watch in Vue.js

Realizziamo un esempio di un componente Vue.js con un campo di input per inserire il raggio del cerchio e sotto un paragrafo che mostra dinamicamente l’area calcolata del cerchio utilizzando una watch property:

<template>
    <div>
      <label for="radius">Raggio del cerchio:</label>
      <input type="number" id="radius" v-model="radius">
      <p>L'area del cerchio è: {{ area }}</p>
    </div>
  </template>
 
<script>  
  export default {
    name: 'WatchComponent',
    data() {
      return {
        radius: 0,
        area: 0
      };
    },
    watch: {
        radius(newValue) {
           this.area = Math.PI * Math.pow(newValue, 2);
        }
    }
  };
  </script>
 

Ho dunque inserito un campo di input per il raggio del cerchio, legato alla variabile radius tramite v-model, inizializzata a 0. Ho anche inizializzato la variabile area che compare in un paragrafo a 0. Dopo ho utilizzato un watcher per osservare i cambiamenti nella variabile radius. Ogni volta che radius cambia, il watcher calcola l’area del cerchio e aggiorna la variabile area.

Differenza con computed

Se avessimo utilizzato una computed property, il calcolo dell’area del cerchio verrebbe eseguito solo quando il valore del raggio cambierebbe. Invece, utilizzando watch, la funzione associata è chiamata ogni volta che il valore di radius cambia, indipendentemente dal fatto che sia direttamente correlato al calcolo dell’area o meno. Questo potrebbe comportare una maggiore complessità e meno efficienza nel codice.

Inoltre Vue.js gestisce automaticamente la cache delle computed properties, quindi il valore dell’area verrebbe memorizzato nella cache e ricalcolato solo quando il valore del raggio cambia. Questo può portare a prestazioni migliori rispetto all’utilizzo di un watch.

Dunque nell’esempio precedente sarebbe preferibile usare computed al posto di watch.

Un esempio più appropriato per l’utilizzo di un watcher potrebbe essere il controllo della disponibilità di un prodotto in un negozio online. Supponiamo di avere un’applicazione Vue.js che visualizza i dettagli di un prodotto e dobbiamo controllare se il prodotto è attualmente disponibile o meno nel negozio online. In questo caso, un watcher può essere utilizzato per monitorare i cambiamenti nello stato di disponibilità del prodotto e reagire di conseguenza.

Conclusioni

In conclusione i watcher sono una risorsa fondamentale nel contesto di Vue.js, offrendo agli sviluppatori un meccanismo versatile per monitorare e rispondere a modifiche specifiche all’interno dei dati dell’applicazione. La loro flessibilità consente di eseguire azioni personalizzate in risposta a eventi specifici, estendendo così le capacità di gestione reattiva dei componenti Vue.js.

L’utilizzo accurato dei watcher richiede una valutazione oculata delle necessità dell’applicazione e una comprensione approfondita delle operazioni reattive richieste. Mentre sono preziosi per compiti come il controllo della validità dei dati o l’interazione con servizi esterni, è importante evitare un uso eccessivo che potrebbe compromettere le prestazioni dell’applicazione.

Bibbia Commentata dai nuovi padri

Alcuni link utili

Tutorial JavaScript

Versione rivisitata del gioco dell’impiccato: divertiti ad indovinare le parole ed impara a sviluppare uno dei giochi più famosi.

Slot Machine: segui una guida passo passo per imparare a svilupparne una semplicissima slot machine da zero.

Quiz interattivo: un quiz che permette di testare le conoscenze su determinati argomenti.

Memoria del colore: una sfida divertente che mette alla prova la memoria visiva e la capacità di ricordare sequenze di colori sempre più complesse.

Memory Game: Un’avvincente sfida di concentrazione e me

Computed in Vue.js

Computed in Vue.js

In questa lezione parleremo di computed in Vue.js, una funzionalità fondamentale di Vue.js per gestire la logica reattiva all’interno delle applicazioni.

Le computed properties in Vue.js sono funzioni calcolate dinamicamente che restituiscono un valore in base allo stato dei dati reattivi. Queste proprietà sono memorizzate nella cache e sono ricalcolate solo quando le dipendenze effettive cambiano. Questo significa che se una o più dipendenze cambiano, il valore calcolato sarà aggiornato automaticamente. Le computed properties sono ideali per calcoli derivati da uno o più dati reattivi.

Esempio Computed in Vue.js

Realizziamo un esempio completo di un componente Vue.js che include un campo di input per il raggio del cerchio e mostra dinamicamente l’area calcolata del cerchio utilizzando una computed property:

<template>
  <div>
    <label for="radius">Raggio del cerchio:</label>
    <input type="number" id="radius" v-model="radius">
    <p>L'area del cerchio è: {{ area }}</p>
  </div>
</template>

<script>
import { ref, computed } from 'vue';

export default {
  name: 'CircleArea',
  data() {
    return {
      radius: 0
    };
  },
  computed: {
    area() {
      const areaCerchio = Math.PI * Math.pow(this.radius, 2);
      return areaCerchio.toFixed(2);
    }
  }
};
</script>

In questo esempio ho utilizzato un campo di input per il raggio del cerchio, legato alla variabile radius tramite v-model. Poi ho utilizzato una computed property chiamata area per calcolare dinamicamente l’area del cerchio basata sul valore di radius. Nella sezione data, abbiamo inizializzato radius a 0. Il componente esporta sia radius che area, che possono essere utilizzati nel template.

Computed in Vue.js o Method?

Sviluppiamo lo stesso esempio utilizzando un metodo:

<template>
  <div>
    <label for="radius">Raggio del cerchio:</label>
    <input type="number" id="radius" v-model="radius">
    <p>L'area del cerchio è: {{ calculateArea() }}</p>
  </div>
</template>

<script>
export default {
  name: 'CircleArea',
  data() {
    return {
      radius: 0
    };
  },
  methods: {
    calculateArea() {
      const areaCerchio = Math.PI * Math.pow(this.radius, 2);
      return areaCerchio.toFixed(2); // Arrotonda l'area a due cifre decimali
    }
  }
};
</script>

La differenza principale tra l’utilizzo di una computed property e l’utilizzo di un metodo per calcolare e mostrare l’area del cerchio è nel modo in cui vengono gestiti i dati reattivi e l’ottimizzazione delle prestazioni.

  1. Computed Property:
    • Una computed property è calcolata dinamicamente in base allo stato dei dati reattivi. Vue.js gestisce automaticamente la cache e ricalcola il valore solo quando le dipendenze effettive cambiano.
    • Quando il valore del raggio cambia, Vue.js ricalcola automaticamente l’area del cerchio.
    • Le computed properties sono ideali per calcoli che dipendono da dati reattivi e sono ottimizzate per prestazioni, in quanto vengono memorizzate nella cache e ricalcolate solo quando necessario.
  2. Metodo:
    • Un metodo viene chiamato esplicitamente ogni volta che viene richiesto, ad esempio nel template o in risposta a un evento.
    • Quando il valore del raggio cambia, il metodo deve essere chiamato manualmente per ricalcolare l’area del cerchio e visualizzarla.
    • I metodi possono essere più flessibili e consentono di eseguire operazioni complesse o logiche aggiuntive al di là del semplice calcolo dell’area del cerchio.

L’utilizzo di una computed property in Vue.js per calcolare l’area del cerchio è preferibile quando si tratta di calcoli basati su dati reattivi e si desidera ottimizzare le prestazioni. D’altra parte, l’utilizzo di un metodo può essere più appropriato quando si necessita di flessibilità nell’esecuzione di operazioni complesse o quando non si desidera che il calcolo sia eseguito automaticamente in risposta ai cambiamenti dei dati.

Conclusioni

In conclusione, le computed properties in Vue.js si dimostrano uno strumento potente e flessibile per gestire calcoli basati su dati reattivi. Sfruttando la loro capacità di memorizzare nella cache e ricalcolare i valori solo quando necessario, possiamo ottimizzare le prestazioni delle nostre applicazioni, evitando calcoli ridondanti e migliorando l’esperienza dell’utente.

Bibbia Commentata dai nuovi padri

Alcuni link utili

Tutorial JavaScript

Versione rivisitata del gioco dell’impiccato: divertiti ad indovinare le parole ed impara a sviluppare uno dei giochi più famosi.

Slot Machine: segui una guida passo passo per imparare a svilupparne una semplicissima slot machine da zero.

Quiz interattivo: un quiz che permette di testare le conoscenze su determinati argomenti.

Memoria del colore: una sfida divertente che mette alla prova la memoria visiva e la capacità di ricordare sequenze di colori sempre più complesse.

Memory Game: Un’avvincente sfida di concentrazione e me

Applicazione con OpenLibrary in Vue

Applicazione con OpenLibrary in Vue

In questa lezione realizzeremo un’applicazione con l’uso di OpenLibrary, un progetto open source che si propone di creare un catalogo online completo e accessibile di tutti i libri. È gestito da Internet Archive, una organizzazione non profit che si impegna a preservare il patrimonio culturale digitale.

L’obiettivo principale di OpenLibrary è quello di fornire un’ampia gamma di informazioni sui libri, inclusi dettagli come titolo, autore, editore, anno di pubblicazione, trama e recensioni. Il progetto si basa su contributi volontari e dati disponibili pubblicamente, inclusi dati forniti da biblioteche, editori e utenti.

OpenLibrary offre anche funzionalità aggiuntive come la possibilità di prenotare libri, scrivere recensioni, creare elenchi di lettura personalizzati e altro ancora. L’accesso alle informazioni su OpenLibrary è gratuito e aperto a tutti gli utenti.

Applicazione con OpenLibrary in Vue – esempio

Nel nostro esempio realizzeremo un’applicazione con OpenLibrary in Vue che si occupa di mostrare i libri, effettuare una ricerca e filtrare le categorie.

Per la chiamata API utilizzeremo axios, una libreria JavaScript utilizzata per effettuare richieste HTTP. Viene importata all’inizio del componente per consentire il recupero dei dati dai servizi web, occorre installarla se non è già presente nel progetto con

npm install axios

Realizziamo lo script necessario, includendo un insieme di dati che include:

  • categories: Un array di categorie di libri predefinite.
  • books: Un array vuoto che verrà popolato con i risultati della ricerca dei libri.
  • loading: Una variabile booleana che indica se la ricerca è in corso.
  • searchTerm: Una stringa utilizzata per memorizzare il termine di ricerca inserito dall’utente.

Realizziamo poi questi metodi:

  • searchByCategory(category): Questo metodo viene chiamato quando un utente seleziona una categoria dalla lista predefinita. Imposta il termine di ricerca sulla categoria selezionata e chiama searchBooks() per avviare la ricerca.
  • searchBooks(): Effettua una richiesta HTTP per cercare libri basati sul termine di ricerca memorizzato in searchTerm. Utilizza l’API OpenLibrary per ottenere i risultati di ricerca, limitati a 10 libri. Una volta ottenuti i risultati, popola l’array books con i dati dei libri e chiama getBookCovers() per ottenere le copertine dei libri.
  • getBookCovers(): Per ogni libro trovato nei risultati della ricerca, controlla se è disponibile un’immagine di copertina. Se sì, genera l’URL dell’immagine di copertina utilizzando l’ID della copertina e aggiunge l’URL al libro.
<script>
import axios from 'axios';

export default {
  name: 'App',
  data() {
    return {
      categories: ['Romance', 'Mystery', 'Fiction', 'Fantasy'], // Esempio di categorie
      books: [],
      loading: false,
      searchTerm: ''
    }
  },
  methods: {
    searchByCategory(category) {
      this.searchTerm = category;
      this.searchBooks();
    },
    searchBooks() {
      if (!this.searchTerm) {
        return;
      }
      this.loading = true;
      const url = `https://openlibrary.org/search.json?title=${encodeURIComponent(this.searchTerm)}&limit=10`;
      axios.get(url)
        .then(response => {
          this.books = response.data.docs;
          this.loading = false;
          this.getBookCovers();
        })
        .catch(error => {
          console.error('Error searching books:', error);
          this.loading = false;
        });
    },
    getBookCovers() {
      this.books.forEach(book => {
        if (book.cover_i) {
          const coverUrl = `https://covers.openlibrary.org/b/id/${book.cover_i}-M.jpg`;
          book.coverUrl = coverUrl;
        }
      });
    }
  }
}
</script>

Realizziamo poi il template, dove, sotto il testo introduttivo inseriamo un menù di navigazione che mostra le categorie disponibili per la ricerca. Le categorie vengono visualizzate come elenco non ordinato (<ul>) e ogni categoria è rappresentata da un elemento della lista (<li>). Quando un utente fa clic su una categoria, viene chiamato il metodo searchByCategory(category) per avviare la ricerca dei libri in quella categoria.

Ho inserito anche una casella di ricerca per cercare i libri per titolo. L’input è legato a searchTerm tramite v-model, in modo che il termine di ricerca inserito dall’utente venga memorizzato nell’oggetto dati del componente. L’evento @input viene utilizzato per chiamare il metodo searchBooks() ogni volta che l’utente modifica il contenuto della casella di ricerca.

Poi nella sezione principale, viene mostrato un messaggio di “Caricamento…” quando loading è true, indicando che la ricerca è in corso. Se loading è false, viene visualizzata la lista dei libri trovati. Ogni libro è rappresentato da un elemento <div> con la classe “book-card”. Per ogni libro, vengono visualizzati il titolo, l’autore (se disponibile), l’anno di pubblicazione (se disponibile) e l’immagine di copertina (se disponibile).

Ecco dunque come si presenta il template di esempio:

<template>
  <div id="app">
    <header>
      <h1>Open Library Book Search</h1>
      <p> Filtra per: </p>
      <nav>
        <ul>
          <li v-for="category in categories" :key="category" @click="searchByCategory(category)">
           {{ category }}
          </li>
        </ul>
        <input type="text" v-model="searchTerm" @input="searchBooks" placeholder="Cerca per titolo">
      </nav>
    </header>
    <main>
      <h2> Benvenuti nella nostra libreria</h2>
      <div v-if="loading">
        Caricamento...</div>
      <div v-else class="book-list">
        <div v-for="book in books" :key="book.key" class="book-card">
          <h2>{{ book.title }}</h2>
          <p v-if="book.author_name">Autore: {{ book.author_name.join(', ') }}</p>
          <p v-if="book.first_publish_year">Anno di pubblicazione: {{ book.first_publish_year }}</p>
          <img v-if="book.coverUrl" :src="book.coverUrl" alt="Cover">
        </div>
      </div>
    </main>
  </div>
</template>

Conclusioni

In questa lezione abbiamo realizzato un’applicazione con OpenLibrary in Vue, in un unico componente, anche in questo caso potremmo gestire il tutto con più componenti.

Alcuni link utili

Tutorial JavaScript

Versione rivisitata del gioco dell’impiccato: divertiti ad indovinare le parole ed impara a sviluppare uno dei giochi più famosi.

Slot Machine: segui una guida passo passo per imparare a svilupparne una semplicissima slot machine da zero.

Quiz interattivo: un quiz che permette di testare le conoscenze su determinati argomenti.

Memoria del colore: una sfida divertente che mette alla prova la memoria visiva e la capacità di ricordare sequenze di colori sempre più complesse.

Memory Game: Un’avvincente sfida di concentrazione e me

Visualizzare libri da un file JSON

Visualizzare libri da un file JSON

In questa lezione impararemo a visualizzare dei libri da un file JSON. Ricordiamo che la visualizzazione dei dati da un file JSON è un’operazione comune nello sviluppo di applicazioni web e mobili poiché i file JSON forniscono un modo efficace per organizzare e trasferire dati strutturati.

Visualizzare libri da un file JSON – esempio

Supponiamo dunque di avere un file json che contiene dei libri a piacere con i dati di autori, categoria, cover e primo anno di pubblicazione. Prendo l’immagine della cover dalla API gratuita openlibrary.

Chiaramente potete aggiungere tanti altri libri a piacere, io ho creato questo file di esempio:

[
    {
      "title": "Il Signore degli Anelli",
      "author": "J.R.R. Tolkien",
      "category": "Fantasy",
      "coverUrl": "https://covers.openlibrary.org/b/id/0013119612-M.jpg",
      "first_publish_year": 1954
    },
    {
      "title": "Orgoglio e pregiudizio",
      "author": "Jane Austen",
      "category": "Romanzo",
      "coverUrl": "https://covers.openlibrary.org/b/id/14552692-M.jpg",
      "first_publish_year": 1813
    },
    {
      "title": "Il fu Mattia Pascal",
      "author": "Luigi Pirandello",
      "category": "Romanzo",
      "coverUrl": "https://covers.openlibrary.org/b/id/0010362119-L.jpg",
      "first_publish_year": 1949
    },
    {
      "title": "Il Trono di Spade",
      "author": "George R.R. Martin",
      "category": "Fantasy",
      "coverUrl": "https://covers.openlibrary.org/b/id/9269962-M.jpg",
      "first_publish_year": 1996
    },
    {
      "title": "Harry Potter e la pietra filosofale",
      "author": "J.K. Rowling",
      "category": "Fantasy",
      "coverUrl": "https://covers.openlibrary.org/b/id/0012373652-M.jpg",
      "first_publish_year": 1997
    },

    {
      "title": "Don Chisciotte",
      "author": "Miguel de Cervantes",
      "category": "Classici",
      "coverUrl": "https://covers.openlibrary.org/b/id/7977593-L.jpg",
      "first_publish_year": 1905
    }
  ]
  

Ho inserito questo file per semplicità all’interno della cartella assets.

Componente per la visualizzazione dei libri – script

Nello script importiamo il file books.json che contiene i dati dei libri.

Nel blocco data() definiamo i dati del componente Vue. Nel nostro questo caso, ci sono gli attributi:

  • books: un array vuoto che verrà popolato con i dati dei libri.
  • loading: una variabile booleana che indica lo stato di caricamento dei dati.
  • selectedCategory: una stringa vuota che rappresenta la categoria selezionata dall’utente.

Poi nella computed inseriamo le proprietà

  • allCategories che restituisce un array di tutte le categorie presenti nei libri. Utilizza un Set per assicurarsi che le categorie siano uniche e quindi trasforma il set in un array utilizzando Array.from().
  • displayedBooks che filtra i libri in base alla categoria selezionata dall’utente (selectedCategory). Se nessuna categoria è stata selezionata, restituisce tutti i libri; altrimenti, restituisce solo i libri che corrispondono alla categoria selezionata.

Infine il metodo filterBooks() viene chiamato quando il componente viene creato (created()) per caricare i dati dei libri dal file JSON (booksData). Inoltre, imposta la variabile loading su true prima del caricamento e su false dopo aver completato il caricamento.

Ecco dunque il codice di esempio:

<script>
import booksData from '@/assets/books.json';

export default {
  data() {
    return {
      books: [],
      loading: true,
      selectedCategory: '',
    };
  },
  computed: {
    allCategories() {
      const categories = new Set();
      this.books.forEach(book => categories.add(book.category));
      return Array.from(categories);
    },
    displayedBooks() {
      if (!this.selectedCategory) {
        return this.books;
      }
      return this.books.filter(book => book.category === this.selectedCategory);
    },
  },
  methods: {
    filterBooks() {
      this.loading = true;
        this.books = booksData;
        this.loading = false;
    },
  },
  created() {
    this.filterBooks();
  },
};
</script>

Componente per la visualizzazione dei libri – template

Dopo ho creato il componente che interagisce con le API. In questa fase ho utilizzato un unico componente per semplificare le operazioni.

Il template HTML contiene la struttura dell’applicazione, con un’intestazione (<header>), un corpo principale (<main>) e un elenco di libri all’interno di un contenitore (<div class="container">). I libri sono rappresentati come card all’interno di un wrapper con classe card-wrapper.

Ho inserito una select con la direttiva v-model che stabilisce un legame bidirezionale tra la variabile selectedCategory nel modello Vue e il valore selezionato nell’elemento <select>. Ciò significa che quando si seleziona un’opzione dall’elemento <select>, il valore di selectedCategory viene automaticamente aggiornato per riflettere la selezione dell’utente, e viceversa.

Nella select ho inserito l’evento @change="filterBooks": Questo è un evento Vue che ascolta quando l’utente cambia la selezione nell’elemento <select>. Quando l’utente seleziona un’opzione diversa, viene chiamato il metodo filterBooks() definito nel componente Vue. Questo metodo si occupa di filtrare i libri in base alla categoria selezionata e di aggiornare l’elenco dei libri visualizzati.

All’interno dell’elemento <select>, ci sono due opzioni <option>. La prima opzione ha un valore vuoto "" e un testo “Tutte le categorie”. Questa opzione rappresenta la scelta di visualizzare tutti i libri senza alcun filtro di categoria. La seconda opzione è generata dinamicamente utilizzando v-for e rappresenta ciascuna categoria presente nell’array allCategories. Il testo di ciascuna opzione corrisponde al nome della categoria, mentre il valore è anche il nome della categoria stessa.

Nella sezione dedicata alla card dei libri, con un ciclo v-for di Vue che itera attraverso ciascun libro nell’array displayedBooks. Per ogni libro, viene creato un elemento <div> con la classe card, che rappresenta una card di un libro. L’attributo :key="book.title" viene utilizzato per garantire una corretta identificazione delle card durante il ciclo.

Ecco come ho realizzato il template:

<template>
  <div>
    <header>
      <div class="header-content">
        <h1>Libreria</h1>
        <select v-model="selectedCategory" @change="filterBooks">
          <option value="">Tutte le categorie</option>
          <option v-for="category in allCategories" :key="category" :value="category">{{ category }}</option>
        </select>
      </div>
    </header>
    <main>
    <div class="container">
     <div class="card-wrapper">
      <div v-for="book in displayedBooks" :key="book.title" class="card">
        <div class="card-cover">
          <img :src="book.coverUrl" alt="Cover">
        </div>
        <div class="card-details">
          <h2>{{ book.title }}</h2>
          <div class="book-info">
            <p><strong>Autore:</strong> {{ book.author }}</p>
            <p><strong>Categoria:</strong> {{ book.category }}</p>
            <p><strong>Anno di pubblicazione:</strong> {{ book.first_publish_year }}</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</main>
</div>
</template>

Divisone dei componenti

Potremmo organizzare il codice in componenti separati. Creando ad esempio un HeaderComponent e un MainComponent inseriti in App.Vue. Utilizziamo props ed emit per tale scopo.

Ecco dunque come si presenta App.vue:

<template>
    <div>
      <HeaderComponent :selectedCategory="selectedCategory" :allCategories="allCategories" @categoryChanged="handleCategoryChange" />
      <MainComponent :displayedBooks="displayedBooks" />
    </div>
</template>
  
<script>
  import HeaderComponent from './sections/HeaderComponent.vue';
  import MainComponent from './sections/MainComponent.vue';
  import booksData from '@/assets/books.json';
  
  export default {
    data() {
      return {
        books: [],
        loading: true,
        selectedCategory: '',
      };
    },
    computed: {
      allCategories() {
        const categories = new Set();
        this.books.forEach(book => categories.add(book.category));
        return Array.from(categories);
      },
      displayedBooks() {
        if (!this.selectedCategory) {
          return this.books;
        }
        return this.books.filter(book => book.category === this.selectedCategory);
      },
    },
    methods: {
      handleCategoryChange(category) {
        this.selectedCategory = category;
      },
      filterBooks() {
        this.loading = true;
        this.books = booksData;
        this.loading = false;
      },
    },
    created() {
      this.filterBooks();
    },
    components: {
      HeaderComponent,
      MainComponent
    }
  };
</script> 

Dunque l’HeaderComponent si può sviluppare in questo modo:

<template>
    <header>
      <div class="header-content">
        <h1>Libreria</h1>
        <select :value="selectedCategory" @change="handleChange">
          <option value="">Tutte le categorie</option>
          <option v-for="category in allCategories" :key="category" :value="category">{{ category }}</option>
        </select>
      </div>
    </header>
  </template>
  
<script>
  export default {
    props: {
      selectedCategory: String,
      allCategories: Array
    },
    methods: {
      handleChange(event) {
        this.$emit('category-changed', event.target.value);
      }
    }
  };
</script>  

Ed infine il MainComponent:



<template>
    <main>
        <div class="container">
            <div class="card-wrapper">
                <div v-for="book in displayedBooks" :key="book.title" class="card">
                    <div class="card-cover">
                        <img :src="book.coverUrl" alt="Cover">
                    </div>
                    <div class="card-details">
                        <h2>{{ book.title }}</h2>
                        <div class="book-info">
                            <p><strong>Autore:</strong> {{ book.author }}</p>
                            <p><strong>Categoria:</strong> {{ book.category }}</p>
                            <p><strong>Anno di pubblicazione:</strong> {{ book.first_publish_year }}</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </main>
</template>
  
<script>
  export default {
    props: {
      displayedBooks: Array
    }
  };
</script>

Conclusioni

In questa lezione abbiamo visto come sviluppare un’applicazione per visualizzare dei libri da un file JSON, nella prossima lezione vedremo come interagire con API esterne.

Alcuni link utili

Tutorial JavaScript

Versione rivisitata del gioco dell’impiccato: divertiti ad indovinare le parole ed impara a sviluppare uno dei giochi più famosi.

Slot Machine: segui una guida passo passo per imparare a svilupparne una semplicissima slot machine da zero.

Quiz interattivo: un quiz che permette di testare le conoscenze su determinati argomenti.

Memoria del colore: una sfida divertente che mette alla prova la memoria visiva e la capacità di ricordare sequenze di colori sempre più complesse.

Memory Game: Un’avvincente sfida di concentrazione e me

Dati JSON

Dati JSON

JSON, acronimo di JavaScript Object Notation, è un modo molto pratico ed efficiente di rappresentare e scambiare dati tra diverse applicazioni e sistemi informatici. È come una lingua comune che le applicazioni usano per comunicare tra loro in modo chiaro e conciso.

Immagina JSON come una scatola virtuale che contiene informazioni organizzate in modo specifico. All’interno di questa scatola, abbiamo due tipi principali di elementi:

Oggetti: Questi sono come piccoli contenitori che possono tenere molte informazioni. Ogni oggetto ha delle etichette, chiamate “chiavi”, che identificano i diversi tipi di dati al suo interno. Ad esempio, possiamo avere un oggetto che rappresenta una persona con chiavi come “nome”, “età”, e così via.

{
  "nome": "Paperina",
  "età": 30,
  "studente": true
}

Array: Gli array sono come elenchi di oggetti o valori. Possono contenere molti elementi, tutti raccolti insieme in una sequenza ordinata. Ad esempio, potremmo avere un array di numeri, un array di nomi, o persino un array di oggetti JSON.

["rosso", "verde", "blu", "giallo", "bianco"]

Conversione dati da JSON a JavaScript

JSON.parse() è una funzione integrata di JavaScript che converte una stringa JSON in un oggetto JavaScript. Questa funzione è estremamente utile quando si ricevono dati JSON da una richiesta HTTP o da un’altra fonte e si desidera convertirli in un formato utilizzabile all’interno del codice JavaScript.

Ecco un esempio di utilizzo:

const jsonString = '{"nome": "Paperina", "età": 30}';
const oggetto = JSON.parse(jsonString);

console.log(oggetto.nome); // Output: Paperina
console.log(oggetto.età); // Output: 30

In questo esempio, jsonString contiene una stringa JSON che rappresenta un oggetto con le chiavi “nome” e “età”. Utilizzando JSON.parse(), convertiamo questa stringa JSON in un oggetto JavaScript assegnandola a oggetto. Ora possiamo accedere ai valori all’interno di oggetto come faremmo con qualsiasi altro oggetto JavaScript.

È importante notare che se la stringa JSON non è formattata correttamente, JSON.parse() genererà un errore di analisi e interromperà l’esecuzione dello script.

Ecco perchè di solito si usa un’eccezione:

const jsonString = '{"nome": "Paperina", "età": 30}';

try {
  const oggetto = JSON.parse(jsonString);
  console.log(oggetto.nome);
} catch (errore) {
  console.error('Errore di analisi JSON:', errore);
}

Conversione dati da JavaScript a JSON

È possibile anche fare la conversione inversa. La conversione inversa di JSON.parse() è JSON.stringify(). Quest’ultima funzione converte un oggetto JavaScript in una stringa JSON.

Ecco un esempio di come utilizzare JSON.stringify():

const persona = {
  nome: "Paperina",
  età: 30
};

const jsonString = JSON.stringify(persona);
console.log(jsonString); // Output: '{"nome":"Paperina","età":30}'

In questo esempio, persona è un oggetto JavaScript con le chiavi “nome” e “età”. Utilizzando JSON.stringify(), convertiamo questo oggetto in una stringa JSON e la assegniamo a jsonString.

È importante notare che JSON.stringify() può accettare opzionalmente due parametri aggiuntivi: replacer e spaziatura.

  1. Il parametro replacer consente di personalizzare il processo di serializzazione. È possibile passare una funzione di trasformazione che seleziona quali valori includere nella stringa JSON risultante.
  2. Il parametro spaziatura consente di formattare la stringa JSON risultante con spaziatura per una migliore leggibilità. È possibile specificare il numero di spazi o una stringa di spazi per l’indentazione.

Ecco un esempio di utilizzo di JSON.stringify() con entrambi i parametri opzionali:

const oggetto = {
  nome: "Paperina",
  età: 30
};

const jsonString = JSON.stringify(oggetto, null, 2); // Indenta la stringa con due spazi
console.log(jsonString); // Output formattato:
// {
//   "nome": "Paperina",
//   "età": 30
// }

Questo esempio formatta la stringa JSON risultante con una spaziatura di due spazi per una migliore leggibilità.

Conclusioni

I dati JSON dunque sono facili da capire per gli umani e semplici da elaborare per i computer. Può essere utilizzato in una vasta gamma di situazioni, dalle risposte delle API web ai dati archiviati nei database, e anche nei file di configurazione delle applicazioni.

In breve, JSON è come una lingua universale che le applicazioni utilizzano per comunicare tra loro in modo veloce e affidabile. Con la sua semplicità e versatilità, è diventato uno degli strumenti più importanti nel mondo dello sviluppo software moderno.

Alcuni link utili

Tutorial JavaScript

Versione rivisitata del gioco dell’impiccato: divertiti ad indovinare le parole ed impara a sviluppare uno dei giochi più famosi.

Slot Machine: segui una guida passo passo per imparare a svilupparne una semplicissima slot machine da zero.

Quiz interattivo: un quiz che permette di testare le conoscenze su determinati argomenti.

Memoria del colore: una sfida divertente che mette alla prova la memoria visiva e la capacità di ricordare sequenze di colori sempre più complesse.

Memory Game: Un’avvincente sfida di concentrazione e memoria!