Laravel attivazione Vue JS e creazione dei primi componenti

Integrato con Laravel di default ci sono Vue Js, bootstrap e Sass, oggi ci concentreremo sul primo, avere Vue a portata di mano è molto comodo anche perchè si sposa perfettamente con il framework Php, vedremo ora come iniziare ad utilizzarlo.

Contents

Inizializzazione progetto Laravel

Andiamo velocemente a creare un nuovo progetto Laravel io utilizzo direttamente composer in questo modo:

composer create-project --prefer-dist laravel/laravel exampleVue

Al termine dell’installazione possiamo aprire la cartella della nostra installazione con il nostro editor preferito e andare a settare il file .env. Se non lo troviamo copiamo l’esistente .env.example, possiamo farlo da terminale in questo modo:

cp .env.example .env

Ora settiamo la connessione del nostro database, possiamo utilizzare sqlite oppure mysql o qualsiasi altro database vi venga voglia di utilizzare, anche mongoDB. Una volta fatto questo andiamo a farci aiutare da Laravel a generare la fase di login e creazione di nuovi utenti. Ancora una volta quindi dal terminale lanciamo il seguente comando:

php artisan make:auth

Andiamo a questo punto a creare le tabelle del nostro database sfruttando le migrazioni di default di Laravel. Subito dopo faremo partire il nostro server in modo da poter vedere la nostra applicazione:

php artisan migrate

php artisan serve

A questo punto possiamo tramite il nostro browser andare all’indirizzo http://127.0.0.1:8000/ e vedere la nostra applicazione. Clicchiamo quindi su register e andiamo a creare il nostro utente, una volta creato, automaticamente farà il login e vedrete un menù in alto e una semplice scritta che ci dice che siamo nella dashboard e loggati.

Laravel Mix

Bene ora è arrivato il momento di giocare finalmente con Vue Js. Per fare questo dobbiamo andare a conoscere Laravel Mix, nella nostra cartella root troveremo webpack.mix.js è questo il file che è responsabile della compilazione del codice Sass e del codice Javascript.
Ora se apriamo dentro view/layouts il file app.blade.php vedremo che questa è la struttura della pagina che vediamo sul browser, vediamo che importa anche un file js in questo modo:

<script src="{{ asset('js/app.js') }}" defer></script>

C’è quindi già un collegamento ad un file js che si trova che troviamo nella cartella public/js. Questo file viene compilato, i sorgenti in realtà sono in resource/assets/js. Qui troviamo il nostro file app.js, se apriamo questo file vediamo che importa bootstrap e appunto Vue e un suo componente di esempio che troviamo nella cartella components, subito dopo va a istanziare Vue e a legarlo ad un id ‘app’. Per poter utilizzare questa parte dobbiamo lanciare dal nostro terminale

npm install

E subito dopo facciamo partire l’ascolto delle nostre modifiche con il comando:

npm run watch

Questo rimarrà in ascolto delle modifiche del nostro javascript e automaticamente ricompilerà per noi.
Si può utilizzare ‘npm run dev‘ per compilare invece una sola volta, con ‘npm run production‘ invece verranno anche minificati i file in output.

Componenti Vue Js

È arrivata l’ora di giocare con Vue, quindi ora cercheremo di trasformare la pagina blade in componenti Vue, possiamo iniziare proprio dal menù.

Vue: Componente Menù

Andiamo quindi nella cartella components sotto js, copiamo il file ExampleComponent e chiamiamo il nuovo file Menu.vue, andiamo anche subito a dichiararlo in app.js in questo modo:

Vue.component('nav-menu', require('./components/Menu.vue'));

Adesso andiamo in app.blade.php e andiamo a tagliare il nostro menù per sistemarlo all’interno del nostro nuovo componente appena creato, quindi da resource/view/layouts/app.blade.php andiamo a copiare il nostro menù, e andiamo ad eliminare tutto quello che stà nel lato destro del nostro menù, esattamente togliamo tutto ciò che è nell’ul con classi “navbar-nav ml-auto”, proprio sotto il commento “Right Side Of Navbar”. il nostro componente Menu.vue avrà quindi il seguente template, che avrà il problema abbastanza evidente di variabili stampate in php, ma siamo in javascript ora dobbiamo modificarle:

<template>
    <nav class="navbar navbar-expand-md navbar-light navbar-laravel">
        nav  <div class="container">
        <a class="navbar-brand" href="{{ url('/') }}">
            {{ config('app.name', 'Laravel') }}
        </a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>

        <div class="collapse navbar-collapse" id="navbarSupportedContent">
            <!-- Left Side Of Navbar -->
            <ul class="navbar-nav mr-auto">

            </ul>

            <!-- Right Side Of Navbar -->
            <ul class="navbar-nav ml-auto">
               
            </ul>
        </div>
    </div>
    </nav>
</template>

Bene ora risolviamo subito il problema delle variabili trasformiamo anche lo script che troviamo sempre nella nostra pagina Menu.vue, dichiariamo le variabili che utilizzeremo nel componente in questo modo:

<script>
    export default {
        props:['title', 'url'],
        mounted(){
            console.log('ci siamo');
        }
    }
</script>

Abbiamo dichiarato la variabile title ed url, ora andiamo a modificarle nel template, il file completo quindi diverrà questo:

<template>
    <nav class="navbar navbar-expand-md navbar-light navbar-laravel">
        <div class="container">
            <a class="navbar-brand" v-bind:href="url">
                {{ title }}
            </a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>

            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <!-- Left Side Of Navbar -->
                <ul class="navbar-nav mr-auto">

                </ul>

                <!-- Right Side Of Navbar -->
                <ul class="navbar-nav ml-auto">
                   
                </ul>
            </div>
        </div>
    </nav>
</template>

<script>
    export default {
        props:['title', 'url'],
        mounted(){
            console.log('ci siamo');
        }
    }
</script>

Abbiamo aggiunto nel nostro template le nostre variabili, normalmente le variabili si inseriscono tra doppia parentesi graffa, nel caso di attributi come href invece si utilizza ‘v-bind’. Ora in app.blade.php andiamo a mettere al posto del menu il nostro componente e vediamo di passargli i relativi parametri come attributi:

<nav-menu title="{{ config('app.name', 'Laravel') }}" url="{{ url('/') }}">
</nav-menu>

Se andiamo a provare l’applicazione sul nostro browser ecco che ci sarà il nostro menu, esattamente come prima, ma senza la nostra parte destra. Quindi procediamo ad inserire anche quella, ancora una volta andiamo a modificare il nostro file app.blade.php in questo modo:

<nav-menu title="{{ config('app.name', 'Laravel') }}" url="{{ url('/') }}">
    @guest
        <li><a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a></li>
        <li><a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a></li>
    @else
        <li class="nav-item dropdown">
            <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
                {{ Auth::user()->name }} <span class="caret"></span>
            </a>

            <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                <a class="dropdown-item" href="{{ route('logout') }}"
                   onclick="event.preventDefault();
                                                     document.getElementById('logout-form').submit();">
                    {{ __('Logout') }}
                </a>

                <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
                    @csrf
                </form>
            </div>
        </li>
    @endguest
</nav-menu>

Per fare in modo che ciò che viene passato dentro al tag nav-menu venga visualizzato e nel giusto posto dal componente Menu, andiamo a modificarlo nel seguente modo:

<!-- Right Side Of Navbar -->
<ul class="navbar-nav ml-auto">
    <slot></slot>
</ul>

Il componente Menu a questo punto metterà al posto del placeholder slot il contenuto che è stato passato tra il tag nav-menu.

Vue: Card HomePage

Ora andiamo nel file home.blade.php dentro la cartella views, qui c’è la nostra homepage di amministrazione, quello che troverete è questo:

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">Dashboard</div>

                    <div class="card-body">
                        You are logged in!
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

Come vedete c’è la card che contiene un titolo ‘Dashboard’ e un messaggio che ci avverte che siamo loggati. Si può creare un bellissimo componente card in modo da trasformare anche questa parte di pagina in un componente. Per prima cosa copiamo il nostro Menu.vue in un file che nominiamo Card.vue e andiamo a tagliare e incollare in template tutto il div con classe card, quindi il componente risulterà questo:

<template>
    <div class="card">
        <div class="card-header">Dashboard</div>

        <div class="card-body">
            You are logged in!
        </div>
    </div>
</template>

<script>
    export default {
        mounted(){
            console.log('siamo nella card');
        }
    }
</script>

Chiaramente dobbiamo andare a importare il nostro componente in app.js in questo modo:

Vue.component('card', require('./components/Card.vue'));

Perfetto andiamo a modificare ora anche home.blade.php, inseriamo il componente in questo modo:

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <card></card>
            </div>
        </div>
    </div>
@endsection

Quindi abbiamo richiamato il componente card e lì andiamo semplicemente a stampare la card che era presente direttamente in home, quindi se non vedremo variazioni grafiche aggiornando la nostra pagina vorrà dire che tutto è andato come previsto.
Per finire andiamo a configurare i parametri in ingresso al componente, prendiamo il titolo come input e aggiungiamo il placeholder slot in modo da poter inserire dentro qualsiasi contenuto. Il nostro componente diventerà quindi questo:

<template>
    <div class="card">
        <div class="card-header">{{title}}</div>

        <div class="card-body">
            <slot></slot>
        </div>
    </div>
</template>

<script>
    export default {
        props: ['title'],
        mounted(){
            console.log('siamo nella card');
        }
    }
</script>

Passiamo quindi anche i giusti parametri da home.blade.php :

<card title="Dashbord">
     You are logged in!
</card>

Riutilizziamo il componente card

Bene tutta questa fatica per avere la pagina uguale a prima? E ora? Tutto questo solo per avere i componenti separati?
Andiamo a giocare un po’ con la nostra pagina e un minimo con il nuovo componente creato. Proviamo quindi a riutilizzare ora questa card, che potremmo utilizzare sempre nel progetto in questo modo, modificando solamente la nostra home.blade.php:

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <card title="Dashbord">
                    <card title="Utente Migliore">
                        Massimiliano Salerno
                    </card>
                    <card title="Informazioni Utente">
                        <p>
                            Luogo di Nascita: Roma
                        </p>
                        <p>
                            Età: 35 anni
                        </p>
                    </card>
                </card>
            </div>
        </div>
    </div>
@endsection

Ora la card l’abbiamo riutilizzata e addirittura l’abbiamo anche riutilizzata una dentro un’altra card. Andiamo a rendere leggermente più interessante la parte grafica in questo modo:

<template>
    <div class="card">
        <div class="card-header bg-success">{{title}}</div>

        <div class="card-body">
            <slot></slot>
        </div>
    </div>
</template>

<script>
    export default {
        props: ['title'],
        mounted(){
            console.log('siamo nella card');
        }
    }
</script>

<style scoped>
    .card{
        margin-bottom: 10px;
    }
</style>

A parte la classe bg-primary applicata all’header della card, la cosa molto interessante è quella finale abbiamo applicato uno stile all’elemento con classe card, ma il bello è che aggiungendo in style l’attributo ‘scoped’questo stile sarà applicato solo in questo componente, se utilizzerò fuori da questo componente la classe card non avrà il margine di 10px.

Ora rendiamo il componente ancora più dinamico permettendo che venga passato un ulteriore parametro che detta il colore di sfondo dell’header della card, in questo modo:

<template>
    <div class="card">
        <div class="card-header" v-bind:class="background">{{title}}</div>

        <div class="card-body">
            <slot></slot>
        </div>
    </div>
</template>

<script>
    export default {
        props: ['title', 'background'],
        mounted(){
            console.log(this.background);
            this.background = 'bg-'+this.background;
        }
    }
</script>

<style scoped>
    .card{
        margin-bottom: 10px;
    }
    .card .card-header{
        color:white;
    }
</style>

Per prima cosa abbiamo aggiunto il parametro in ingresso ‘background’, e lo abbiamo inserito nel template con v-bind, quest’ultimo lega ad un attributo una proprietà javascript, chiaramente l’attributo che vogliamo passare è semplicemente ‘primary’, ‘success’ e quindi nel metodo mounted andiamo a modificare il dato che ci arriverà, in modo da aggiungere prima ‘bg-‘, infatti mounted è il metodo che verrà chiamato una volta caricato il componente con i relativi parametri in ingresso.

Passiamo a questo punto al file home.blade.php e iniziamo a mettere le informazioni su due colonne utilizzando le classi di boostrap e passiamo diversi parametri di background in questo modo:

<card title="Dashbord" background="primary">
    <div class="row">
        <div class="col-md-6">
            <card  title="Utente Migliore" background="success">
                Massimiliano Salerno
            </card>
        </div>
        <div class="col-md-6">
            <card title="Informazioni Utente" background="success">
                <p>
                    Luogo di Nascita: Roma
                </p>
                <p>
                    Età: 35 anni
                </p>
            </card>
        </div>

    </div>

</card>

Perfetto, però vogliamo dare un valore di default al background dell’header della nostra card e quindi andiamo a modificare in questo modo la funzione mounted in Card.vue:

mounted(){
     this.background = 'bg-'+ (this.background || 'primary');
}

A questo punto se non passiamo il parametro background al componente automaticamente sarà ‘primary’.
Ora però non vogliamo utilizzare normale css, vogliamo utilizzare sass, quanto è difficile usarlo? Molto molto semplice, basta aggiungere nel nostro componente Card.vue allo style, l’attributo ‘lang’ con valore ‘scss’, nel seguente modo:

<style lang="scss" scoped>
    .card{
        margin-bottom: 10px;
        .card-header{
            color:white;
        }
    }
</style>

Ora possiamo tranquillamente utilizzare sass per scrivere il CSS del nostro componente.
Benissimo ora possiamo iniziare a giocare come meglio preferiamo con i nostri componenti.

2 commenti a “Laravel attivazione Vue JS e creazione dei primi componenti”
  1. Ciao Massimiliano, complimenti, ottimo articolo, l’ ho seguito alla lettere in un nuovo progetto e funziona tutto alla perfezione.
    Volevo però chiederti se possibile, se questi passaggi sono replicabili in un progetto Laravel 8 già esistente in cui non era stato integrato Vue.
    Questo perchè ho provato ad integrarlo nel mio ma ho una serie di problemi.
    1. vari errori npm in console riguardanti webpack-cli
    2. il mio progetto compila il file app.js che si trova sotto Public e non sotto Resource
    3. Sopratutto in console ottengo un “Require is not defined” alla linea Require(‘./bootstrap’)

    avresti idea almeno di come risolvere i punti 2 e 3?

    Per il punto 3 ho provato ad aggiungere al file package.json l’ istruzione “type”: “module” tra gli script ma non è cambiato nulla.

    Grazie

  2. Ciao Alessandro, ti conviene:
    – Installare laravel UI con il seguente comando composer require laravel/ui “^1.0” –dev
    – e poi attivare vue js in questo modo: php artisan ui vue –auth

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *