Introduzione allo Stimulus Framework

Ci sono molti framework JavaScript là fuori. A volte comincio anche a pensare di essere l'unico che non ha ancora creato un quadro. Alcune soluzioni, come Angular, sono grandi e complesse, mentre alcune, come Backbone (che è più una libreria che un framework), sono abbastanza semplici e forniscono solo una manciata di strumenti per accelerare il processo di sviluppo.

Nell'articolo di oggi vorrei presentarvi un nuovissimo framework chiamato Stimulus. È stato creato da un team di Basecamp guidato da David Heinemeier Hansson, uno sviluppatore popolare che era il padre di Ruby on Rails.

Lo stimolo è un piccolo quadro che non è mai stato concepito per diventare qualcosa di grande. Ha una propria filosofia e attitudine allo sviluppo del front-end, che alcuni programmatori potrebbero gradire o non gradire. Stimulus è giovane, ma la versione 1 è già stata rilasciata, quindi dovrebbe essere sicura da usare in produzione. Ho suonato un po 'con questa struttura e mi è piaciuta molto la sua semplicità ed eleganza. Spero che piaccia anche a te!

In questo post discuteremo le basi di Stimulus durante la creazione di un'applicazione a pagina singola con caricamento dati asincrono, eventi, persistenza dello stato e altre cose comuni.

Il codice sorgente può essere trovato su GitHub.

Introduzione allo stimolo

Stimulus è stato creato dagli sviluppatori di Basecamp. Invece di creare applicazioni JavaScript a pagina singola, hanno deciso di scegliere un maestoso monolite basato su Turbolinks e JavaScript. Questo codice JavaScript si è evoluto in un quadro piccolo e modesto che non richiede di passare ore e ore a imparare tutti i suoi concetti e caveat.

Lo stimolo è principalmente pensato per attaccarsi agli elementi DOM esistenti e lavorare con loro in qualche modo. È possibile, tuttavia, anche il rendering dinamico dei contenuti. Tutto sommato, questa struttura è molto diversa dalle altre soluzioni popolari, poiché, ad esempio, persiste nello stato in HTML, non negli oggetti JavaScript. Alcuni sviluppatori potrebbero trovarlo inopportuno, ma danno a Stimulus una possibilità, in quanto potrebbe davvero sorprenderti.

Il framework ha solo tre concetti principali che dovresti ricordare, che sono:

  • Controller: Classi JS con alcuni metodi e callback che si collegano al DOM. L'allegato si verifica quando a dati-controllore L'attributo "magic" appare sulla pagina. La documentazione spiega che questo attributo è un ponte tra HTML e JavaScript, proprio come le classi fungono da ponte tra HTML e CSS. Un controller può essere collegato a più elementi e un elemento può essere attivato da più controller.
  • Azioni: metodi da chiamare su eventi specifici. Sono definiti in speciale Dati-action attributi.
  • obiettivi: elementi importanti che possono essere facilmente accessibili e manipolati. Sono specificati con l'aiuto di data-obiettivo attributi.

Come puoi vedere, gli attributi sopra elencati ti consentono di separare il contenuto dalla logica comportamentale in modo molto semplice e naturale. Più avanti in questo articolo, vedremo tutti questi concetti in azione e noteremo quanto sia facile leggere un documento HTML e capire cosa sta succedendo.

Avvio automatico di un'applicazione di stimolo

Stimulus può essere facilmente installato come pacchetto NPM o caricato direttamente tramite copione tag come spiegato nei documenti. Si noti inoltre che, per impostazione predefinita, questo framework si integra con il gestore asset Webpack, che supporta funzionalità come il caricamento automatico del controller. Sei libero di usare qualsiasi altro sistema di compilazione, ma in questo caso sarà necessario un po 'più di lavoro.

Il modo più rapido per iniziare con Stimulus è utilizzare questo progetto di base che ha già collegato il server Web Express e Babel. Dipende anche da Yarn, quindi assicurati di installarlo. Per clonare il progetto e installare tutte le sue dipendenze, eseguire:

git clone https://github.com/stimulusjs/stimulus-starter.git cd stimulus-starter filato installa

Se preferisci non installare nulla localmente, puoi remixare questo progetto su Glitch e fare tutta la codifica direttamente nel tuo browser.

Fantastico, siamo tutti pronti e possiamo procedere alla sezione successiva!

Alcuni Markup

Supponiamo di creare una piccola applicazione a pagina singola che presenti un elenco di dipendenti e carichi informazioni come nome, foto, posizione, stipendio, data di nascita, ecc..

Iniziamo con l'elenco degli impiegati. Tutto il markup che stiamo per scrivere dovrebbe essere collocato all'interno di pubblico / index.html file, che ha già un HTML molto minimale. Per ora, codificheremo tutti i nostri dipendenti nel seguente modo:

 

I nostri dipendenti

  • John Doe
  • Alice Smith
  • Will Brown
  • Ann Gray

Bello! Ora aggiungiamo un pizzico di magia Stimulus.

Creare un controller

Come spiega la documentazione ufficiale, lo scopo principale di Stimulus è connettere oggetti JavaScript (chiamati controllori) agli elementi DOM. I controllori daranno poi vita alla pagina. Come convenzione, i nomi dei controllori dovrebbero terminare con a _controller postfix (che dovrebbe essere molto familiare agli sviluppatori di Rails).

È disponibile una directory per i controller già disponibili src / controller. Dentro, troverai un  hello_controller.js file che definisce una classe vuota:

import Controller dalla classe di esportazione predefinita "stimulus" estende Controller  

Rinominiamo questo file in employees_controller.js. Non abbiamo bisogno di richiederlo specificamente perché i controller sono caricati automaticamente grazie alle seguenti righe di codice in src / index.js file:

const application = Application.start () const context = require.context ("./ controller", true, /\.js$/) application.load (definitionsFromContext (context))

Il prossimo passo è connettere il nostro controller al DOM. Per fare ciò, imposta a dati-controllore attributo e assegnargli un identificatore (che è dipendenti nel nostro caso):

Questo è tutto! Il controller è ora collegato al DOM.

Callback del ciclo di vita

Una cosa importante da sapere sui controller è che hanno tre callback del ciclo di vita che vengono attivati ​​in condizioni specifiche:

  • inizializzare: questa callback avviene solo una volta, quando il controller viene istanziato.
  • Collegare: si attiva ogni volta che colleghiamo il controller all'elemento DOM. Poiché un controller può essere connesso a più elementi nella pagina, questa callback può essere eseguita più volte.
  • disconnect: come probabilmente avete indovinato, questa callback viene eseguita ogni volta che il controller si disconnette dall'elemento DOM.

Niente di complesso, giusto? Approfittiamo del inizializzare() e Collegare() callback per assicurarsi che il nostro controller funzioni effettivamente:

// src / controllers / employees_controller.js esportazione La classe predefinita estende Controller initialize () console.log ('Initialized') console.log (this) connect () console.log ('Connected') console.log ( Questo)  

Quindi, avviare il server eseguendo:

inizio del filo

Navigare verso http: // localhost: 9000. Apri la console del browser e assicurati che entrambi i messaggi siano visualizzati. Significa che tutto funziona come previsto!

Aggiungere eventi

Il prossimo concetto centrale di Stimulus è eventi. Gli eventi sono utilizzati per rispondere alle varie azioni dell'utente nella pagina: clic, hovering, messa a fuoco, ecc. Stimulus non tenta di reinventare una bicicletta e il suo sistema di eventi si basa su eventi JS generici.

Ad esempio, leghiamo un evento click ai nostri dipendenti. Ogni volta che succede questo evento, mi piacerebbe chiamare l'ancora inesistente scegliere() metodo del employees_controller:

 
  • i dipendenti # scelgono "> John Doe
  • i dipendenti # scelgono "> Alice Smith
  • i dipendenti # scelgono "> Will Brown
  • i dipendenti # scelgono "> Ann Gray

Probabilmente, puoi capire cosa sta succedendo qui da solo.

  • Dati-action è l'attributo speciale che associa un evento all'elemento e spiega quale azione deve essere chiamata.
  • clic, ovviamente, è il nome dell'evento.
  • dipendenti è l'identificatore del nostro controller.
  • scegliere è il nome del metodo che vorremmo chiamare.

Da clic è l'evento più comune, può essere tranquillamente omesso:

  • John Doe
  • In questo caso, clic sarà usato implicitamente.

    Quindi, scriviamo il codice scegliere() metodo. Non voglio che si verifichi l'azione predefinita (che è, ovviamente, l'apertura di una nuova pagina specificata nel file href attributo), quindi evitiamolo:

    // src / controllers / employees_controller.js // callback qui ... choose (e) e.preventDefault () console.log (this) console.log (e)

    e è l'oggetto evento speciale che contiene informazioni complete sull'evento innescato. Nota, a proposito Questo restituisce il controller stesso, non un singolo collegamento! Per poter accedere all'elemento che funge da bersaglio dell'evento, usa e.target.

    Ricarica la pagina, fai clic su una voce dell'elenco e osserva il risultato!

    Lavorare con lo stato

    Ora che abbiamo associato un gestore di eventi click ai dipendenti, vorrei memorizzare la persona attualmente selezionata. Perché? Dopo aver memorizzato queste informazioni, possiamo impedire che lo stesso dipendente venga selezionato la seconda volta. Questo ci consentirà in seguito di evitare di caricare le stesse informazioni più volte.

    Stimulus ci insegna a mantenere lo stato nell'API dati, che sembra abbastanza ragionevole. Prima di tutto, forniamo alcuni ID arbitrari per ogni dipendente che usa il Dati-id attributo:

     
    • John Doe
    • i dipendenti # scelgono "> Alice Smith
    • i dipendenti # scelgono "> Will Brown
    • i dipendenti # scelgono "> Ann Gray

    Successivamente, dobbiamo recuperare l'id e persisterlo. L'utilizzo dell'API dati è molto comune con Stimulus, quindi è speciale this.data oggetto è fornito per ogni controller. Con il suo aiuto, possiamo eseguire i seguenti metodi:

    • this.data.get ( 'name'): ottieni il valore dal suo attributo.
    • this.data.set ('nome', valore): imposta il valore sotto qualche attributo.
    • this.data.has ( 'name'): controlla se l'attributo esiste (restituisce un valore booleano).

    Sfortunatamente, queste scorciatoie non sono disponibili per gli obiettivi degli eventi click, quindi dobbiamo restare fedeli getAttribute () nel loro caso:

     // src / controllers / employees_controller.js scegli (e) e.preventDefault () this.data.set ("current-employee", e.target.getAttribute ('data-id'))

    Ma possiamo fare ancora meglio creando un getter e un setter per il currentEmployee:

     // src / controller / employees_controller.js get currentEmployee () return this.data.get ("current-employee") imposta currentEmployee (id) if (this.currentEmployee! == id) this.data.set ("attuale impiegato", id)

    Nota come stiamo usando il this.currentEmployee getter e assicurandosi che l'id fornito non sia lo stesso di quello già memorizzato.

    Ora puoi riscrivere il scegliere() metodo nel modo seguente:

     // src / controllers / employees_controller.js choose (e) e.preventDefault () this.currentEmployee = e.target.getAttribute ('data-id')

    Ricarica la pagina per assicurarti che tutto funzioni ancora. Non noterai alcun cambiamento visivo, ma con l'aiuto dello strumento Inspector noterai che il ul ha il data-dipendenti-corrente-dipendente attributo con un valore che cambia quando si fa clic sui collegamenti. Il dipendenti la parte nel nome dell'attributo è l'identificatore del controllore e viene aggiunta automaticamente.

    Ora passiamo a evidenziare il dipendente attualmente selezionato.

    Usando i bersagli

    Quando un dipendente è selezionato, vorrei assegnare l'elemento corrispondente con a .scelto classe. Ovviamente, potremmo aver risolto questo compito utilizzando alcune funzioni di selettore JS, ma Stimulus fornisce una soluzione migliore.

    Raggiungi obiettivi, che ti consentono di contrassegnare uno o più elementi importanti nella pagina. Questi elementi possono quindi essere facilmente accessibili e manipolati secondo necessità. Per creare un obiettivo, aggiungi a data-obiettivo attributo con il valore di Controller. Nome_destinazione (che si chiama a descrittore di destinazione):

     
    • John Doe
    • i dipendenti # scelgono "> Alice Smith
    • i dipendenti # scelgono "> Will Brown
    • i dipendenti # scelgono "> Ann Gray

    Ora lascia che Stimulus conosca questi nuovi obiettivi definendo un nuovo valore statico:

    // src / controllers / employees_controller.js esportazione La classe predefinita estende Controller static targets = ["employee"] // ...

    Come possiamo accedere agli obiettivi ora? È semplice come dire this.employeeTarget (per ottenere il primo elemento) o this.employeeTargets (per ottenere tutti gli elementi):

     // src / controllers / employees_controller.js choose (e) e.preventDefault () this.currentEmployee = e.target.getAttribute ('data-id') console.log (this.employeeTargets) console.log (this.employeeTarget) )

    Grande! Come possono questi obiettivi aiutarci ora? Bene, possiamo usarli per aggiungere e rimuovere classi CSS con facilità in base ad alcuni criteri:

     // src / controllers / employees_controller.js scegli (e) e.preventDefault () this.currentEmployee = e.target.getAttribute ('data-id') this.employeeTargets.forEach ((el, i) => el .classList.toggle ("chosen", this.currentEmployee === el.getAttribute ("data-id")))

    L'idea è semplice: iteriamo su una serie di bersagli e per ogni target ne paragoniamo Dati-id a quello memorizzato sotto this.currentEmployee. Se corrisponde, all'elemento viene assegnato il .scelto classe. Altrimenti, questa classe viene rimossa. Puoi anche estrarre il if (this.currentEmployee! == id) condizione dal setter e usarlo nel scelto() metodo invece:

     // src / controllers / employees_controller.js scegli (e) e.preventDefault () const id = e.target.getAttribute ('data-id') if (this.currentEmployee! == id) // <--- this.currentEmployee = id this.employeeTargets.forEach((el, i) => el.classList.toggle ("chosen", id === el.getAttribute ("data-id")))

    Bello! Infine, forniremo uno stile molto semplice per il .scelto classe dentro il pubblico / main.css:

    .scelto font-weight: bold; decorazione del testo: nessuna; cursore: predefinito; 

    Ricarica di nuovo la pagina, fai clic su una persona e assicurati che la persona venga evidenziata correttamente.

    Caricamento dei dati in modo asincrono

    Il nostro prossimo compito è caricare le informazioni sul dipendente scelto. In un'applicazione reale, è necessario configurare un provider di hosting, un back-end alimentato da qualcosa come Django o Rails e un endpoint API che risponde con JSON contenente tutti i dati necessari. Ma renderemo le cose un po 'più semplici e ci concentreremo solo sul lato client. Creare un dipendenti directory sotto il pubblico cartella. Successivamente, aggiungi quattro file contenenti dati per i singoli dipendenti:

    1.json

    "nome": "John Doe", "genere": "maschio", "età": "40", "posizione": "CEO", "stipendio": "$ 120.000 / anno", "immagine": "https : //burst.shopifycdn.com/photos/couple-in-love-at-sunset_373x.jpg " 

    2.json

    "nome": "Alice Smith", "genere": "femmina", "età": "32", "posizione": "CTO", "stipendio": "$ 100.000 / anno", "immagine": "https : //burst.shopifycdn.com/photos/woman-listening-at-team-meeting_373x.jpg " 

    3.json

    "name": "Will Brown", "gender": "male", "age": "30", "position": "Tech Lead", "salary": "$ 80.000 / year", "image": " https://burst.shopifycdn.com/photos/casual-urban-menswear_373x.jpg " 

    4.json

    "nome": "Ann Gray", "genere": "femmina", "età": "25", "posizione": "Junior Dev", "stipendio": "$ 20.000 / anno", "immagine": " https://burst.shopifycdn.com/photos/woman-using-tablet_373x.jpg " 

    Tutte le foto sono state prese dalla fotografia di scorta gratuita di Shopify chiamata Burst.

    I nostri dati sono pronti e in attesa di essere caricati! Per fare ciò, codificheremo un codice separato loadInfoFor () metodo:

     // src / controllers / employees_controller.js loadInfoFor (employee_id) fetch ('employees / $ employee_id .json') .then (response => response.text ()) .then (json => this.displayInfo ( json))

    Questo metodo accetta l'id di un dipendente e invia una richiesta di recupero asincrona all'URI specificato. Ci sono anche due promesse: una per recuperare il corpo e un'altra per visualizzare le informazioni caricate (aggiungeremo il metodo corrispondente in un momento).

    Utilizza questo nuovo metodo all'interno scegliere():

     // src / controllers / employees_controller.js scegli (e) e.preventDefault () const id = e.target.getAttribute ('data-id') if (this.currentEmployee! == id) this.loadInfoFor (id ) // ...

    Prima di codificare il displayInfo () metodo, abbiamo bisogno di un elemento per rendere effettivamente i dati a. Perché non sfruttiamo ancora una volta gli obiettivi?

     

    Definisci l'obiettivo:

    // src / controllers / employees_controller.js La classe predefinita di esportazione estende Controller static targets = ["employee", "info"] // ...

    E ora utilizzalo per visualizzare tutte le informazioni:

     // src / controller / employees_controller.js displayInfo (raw_json) const info = JSON.parse (raw_json) const html = '
    • Nome: $ info.name
    • Sesso: $ info.gender
    • Età: $ info.age
    • Posizione: $ info.position
    • Salario: $ info.salary
    'this.infoTarget.innerHTML = html

    Ovviamente, sei libero di utilizzare un motore di template come Handlebars, ma per questo semplice caso probabilmente sarebbe eccessivo.

    Ora ricarica la pagina e scegli uno dei dipendenti. La sua biografia e immagine dovrebbero essere caricate quasi istantaneamente, il che significa che la nostra app funziona correttamente!

    Elenco dinamico dei dipendenti

    Utilizzando l'approccio descritto sopra, possiamo andare ancora oltre e caricare l'elenco dei dipendenti al volo piuttosto che codificarlo.

    Preparare i dati all'interno del pubblico / employees.json file:

    ["id": "1", "nome": "John Doe", "id": "2", "nome": "Alice Smith", "id": "3", "nome ":" Will Brown ", " id ":" 4 "," nome ":" Ann Gray "]

    Ora modificare il pubblico / index.html file rimuovendo la lista hard-coded e aggiungendo a data-dipendenti-url attributo (nota che dobbiamo fornire il nome del controller, altrimenti l'API di dati non funzionerà):

    Non appena il controller è collegato al DOM, dovrebbe inviare una richiesta di recupero per creare un elenco di dipendenti. Significa che il Collegare() callback è il posto perfetto per farlo:

     // src / controller / employees_controller.js connect () this.loadFrom (this.data.get ('url'), this.displayEmployees)

    Propongo di creare un più generico LoadFrom () metodo che accetta un URL per caricare dati da e un callback per rendere effettivamente questi dati:

     // src / controllers / employees_controller.js loadFrom (url, callback) fetch (url) .then (response => response.text ()) .then (json => callback.call (this, JSON.parse (json )))

    Tweak the scegliere() metodo per sfruttare il LoadFrom ():

     // src / controllers / employees_controller.js scegli (e) e.preventDefault () const id = e.target.getAttribute ('data-id') if (this.currentEmployee! == id) this.loadFrom (' dipendenti / $ id .json ', this.displayInfo) // <--- this.currentEmployee = id this.employeeTargets.forEach((el, i) => el.classList.toggle ("chosen", id === el.getAttribute ("data-id")))

    displayInfo () può anche essere semplificato, dal momento che JSON viene ora analizzato direttamente all'interno di LoadFrom ():

     // src / controller / employees_controller.js displayInfo (informazioni) const html = '
    • Nome: $ info.name
    • Sesso: $ info.gender
    • Età: $ info.age
    • Posizione: $ info.position
    • Salario: $ info.salary
    'this.infoTarget.innerHTML = html

    Rimuovere loadInfoFor () e codifica il displayEmployees () metodo:

     // src / controller / employees_controller.js displayEmployees (dipendenti) let html = "
      "employees.forEach ((el) => html + = '
    • $ El.name
    • ') html + = "
    "this.element.innerHTML + = html

    Questo è tutto! Ora stiamo rendendo dinamicamente il nostro elenco di dipendenti in base ai dati restituiti dal server.

    Conclusione

    In questo articolo abbiamo trattato un modesto framework JavaScript chiamato Stimulus. Abbiamo visto come creare una nuova applicazione, aggiungere un controller con una serie di callback e azioni e introdurre eventi e azioni. Inoltre, abbiamo eseguito un caricamento asincrono dei dati con l'aiuto delle richieste di recupero.

    Tutto sommato, questo è tutto per le basi di Stimulus: non ci si aspetta davvero che tu abbia una conoscenza arcana per creare applicazioni web. Ovviamente, il framework avrà probabilmente alcune nuove funzionalità in futuro, ma gli sviluppatori non hanno intenzione di trasformarlo in un enorme mostro con centinaia di strumenti. 

    Se desideri trovare altri esempi di utilizzo di Stimulus, puoi anche consultare questo piccolo manuale. E se stai cercando altre risorse JavaScript da studiare o da utilizzare nel tuo lavoro, dai un'occhiata a ciò che abbiamo a disposizione nel mercato Envato. 

    Ti è piaciuto Stimulus? Saresti interessato a provare a creare un'applicazione reale basata su questo framework? Condividi i tuoi pensieri nei commenti!

    Come sempre, ti ringrazio per essere stato con me e fino alla prossima volta.