Introducere în cadrul de stimulare

Există o mulțime de cadre JavaScript acolo. Uneori chiar încep să cred că sunt singurul care nu a creat încă un cadru. Unele soluții, cum ar fi Angular, sunt mari și complexe, în timp ce unele, cum ar fi Backbone (care este mai mult o bibliotecă decât un cadru), sunt destul de simple și oferă doar o mână de instrumente pentru a accelera procesul de dezvoltare.

În articolul de astăzi aș dori să vă prezint un nou model numit Stimul. A fost creată de o echipă de bază, condusă de David Heinemeier Hansson, un dezvoltator popular care a fost tatăl lui Ruby on Rails.

Stimularea este un cadru mic care nu a fost niciodată intenționat să crească în ceva mare. Are propria sa filozofie și atitudine față de dezvoltarea front-end, pe care unii programatori ar putea să-i placă sau să nu-i placă. Stimularea este tânără, dar versiunea 1 a fost deja lansată, astfel încât ar trebui să fie sigură de a fi utilizată în producție. Am jucat destul de mult cu acest cadru și mi-a plăcut simplitatea și eleganța. Sperăm că vă veți bucura de ea!

În acest articol vom discuta despre elementele de bază ale Stimulului în timp ce creați o aplicație de o singură pagină cu încărcare asincronă a datelor, evenimente, persistență de stat și alte lucruri obișnuite.

Codul sursă poate fi găsit pe GitHub.

Introducere în Stimul

Stimul a fost creat de dezvoltatori la Basecamp. În loc să creeze aplicații JavaScript cu o singură pagină, ei au decis să aleagă un monolit maiestuos alimentat de Turbolinks și unele JavaScript. Acest cod JavaScript a evoluat într-un cadru mic și modest, care nu vă obligă să vă petreceți orele și orele învățând toate conceptele și avertismentele sale.

Stimulul este destinat în principal să se atașeze elementelor DOM existente și să lucreze cu ele într-un fel. Este posibil, totuși, să facem în mod dinamic conținutul. În general, acest cadru este destul de diferit de alte soluții populare, deoarece, de exemplu, persistă statul în HTML, nu în obiectele JavaScript. Unii dezvoltatori pot considera că este incomod, dar oferă Stimulului o șansă, deoarece poate chiar să vă surprindă.

Cadrul are doar trei concepte principale pe care ar trebui să le amintiți, care sunt:

  • controlerele: Clase JS cu câteva metode și callback-uri care se atașează la DOM. Atașamentul se întâmplă când a date-controler Atributul "magic" apare pe pagină. Documentația explică faptul că acest atribut este o punte între HTML și JavaScript, la fel cum clasele servesc drept punți între HTML și CSS. Un controler poate fi atașat la mai multe elemente, iar un element poate fi alimentat de mai multe controale.
  • acţiuni: metode care trebuie apelate la evenimente specifice. Acestea sunt definite în mod special date de acțiune atribute.
  • Obiective: elemente importante care pot fi ușor accesate și manipulate. Acestea sunt specificate cu ajutorul date-țintă atribute.

După cum puteți vedea, atributele enumerate mai sus vă permit să separați conținutul de logica comportamentului într-un mod foarte simplu și natural. Mai târziu, în acest articol, vom vedea toate aceste concepte în acțiune și vom observa cât de ușor este să citiți un document HTML și să înțelegeți ce se întâmplă.

Bootstrapping o cerere de stimulare

Stimulul poate fi ușor instalat ca un pachet NPM sau încărcat direct prin scenariu așa cum este explicat în docs. De asemenea, rețineți că, în mod implicit, acest cadru se integrează cu managerul de active Webpack, care acceptă bunuri cum ar fi controlerul autoloading. Sunteți liber să utilizați orice alt sistem de construcție, dar în acest caz va fi nevoie de mai multă muncă.

Cea mai rapidă modalitate de a începe cu Stimul este prin utilizarea acestui proiect demaror, care are serverul de web Express și Babel deja conectat. De asemenea, depinde de Fire, deci asigurați-vă că ați instalat-o. Pentru a clona proiectul și a instala toate dependențele acestuia, rulați:

git clone https://github.com/stimulusjs/stimulus-starter.git cd stimul-starter fire instalare

Dacă preferați să nu instalați nimic local, puteți remixa acest proiect pe Glitch și faceți tot codul în browser.

Mare - suntem cu toții pregătiți și putem trece la următoarea secțiune!

Unele marcări

Să presupunem că creăm o mică aplicație de o singură pagină care prezintă o listă de angajați și încarcă informații precum numele, fotografia, poziția, salariul, data nașterii etc..

Să începem cu lista angajaților. Toate marcările pe care le vom scrie trebuie plasate în interiorul publice / index.html fișier, care are deja unele HTML foarte puțin. Pentru moment, vom codifica greu angajații noștri în felul următor:

 

Angajații noștri

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

Frumos! Acum, să adăugăm o ruptură de magie Stimul.

Crearea unui controler

După cum explică documentația oficială, scopul principal al Stimulului este de a conecta obiectele JavaScript (numite controlere) la elementele DOM. Controlerele vor aduce la viață pagina. Ca o convenție, numele controlorilor ar trebui să se încheie cu o _controlor postfix (care ar trebui să fie foarte familiar dezvoltatorilor Rails).

Există un director pentru controlorii deja disponibili numiți src / controlere. În interior, veți găsi a  hello_controller.js fișier care definește o clasă goală:

importul Controller din clasa implicită de export "stimul" extinde Controller  

Să redenumiți acest fișier employees_controller.js. Nu este nevoie să solicităm acest lucru în mod special, deoarece controlerii sunt încărcați automat datorită următoarelor linii de cod din src / index.js fişier:

const aplicație = Application.start () const context = require.context ("./ controllers", true, /\.js$/) application.load (definitionsFromContext (context))

Următorul pas este să conectăm controlerul nostru la DOM. Pentru a face acest lucru, setați a date-controler atribuie și atribuie un identificator (care este angajați în cazul nostru):

Asta e! Controlorul este acum atașat la DOM.

Cicluri de apel pentru ciclul de viață

Un lucru important de știut despre controlorii este că au trei apeluri de apel pe durata ciclului de viață care sunt concediați în condiții specifice:

  • inițializa: acest apel invers se întâmplă o singură dată, când controlerul este instanțiat.
  • conectați: se declanșează ori de câte ori conectăm controlerul la elementul DOM. Deoarece un controler poate fi conectat la mai multe elemente din pagină, acest apel invers poate să ruleze de mai multe ori.
  • deconecta: după cum probabil ați ghicit, această invitație de apel rulează ori de câte ori controlerul se deconectează de la elementul DOM.

Nimic complex, nu? Să profităm de inițializa () și conectați() apeluri inverse pentru a ne asigura că operatorul nostru funcționează efectiv:

// console.log ('initialized') console.log acest)  

Apoi, porniți serverul rulând:

fire start

Navigheaza catre http: // localhost: 9000. Deschideți consola browserului dvs. și asigurați-vă că ambele mesaje sunt afișate. Aceasta înseamnă că totul funcționează așa cum era de așteptat!

Adăugarea de evenimente

Următorul concept de Stimul de bază este evenimente. Evenimentele sunt folosite pentru a răspunde diferitelor acțiuni ale utilizatorilor de pe pagină: clic, plasare, focalizare etc. Stimulul nu încearcă să reinventeze o bicicletă, iar sistemul său de evenimente se bazează pe evenimente JS generice.

De exemplu, să angajăm angajații noștri un eveniment de clic. Ori de câte ori se întâmplă acest eveniment, aș dori să sun apelul încă inexistent alege() metodă a employees_controller:

 
  • angajații # selectați "> John Doe
  • angajați # alege "> Alice Smith
  • angajații # alege "> Will Brown
  • angajații # selectați "> Ann Grey

Probabil, puteți înțelege ce se întâmplă aici de unul singur.

  • date de acțiune este atributul special care leagă un eveniment elementului și explică ce acțiuni ar trebui să fie numite.
  • clic, desigur, este numele evenimentului.
  • angajați este identificatorul controlorului nostru.
  • alege este numele metodei pe care dorim să o apelam.

De cand clic este evenimentul cel mai frecvent, poate fi omis în siguranță:

  • John Doe
  • În acest caz, clic vor fi utilizate implicit.

    Apoi, să codificăm alege() metodă. Nu vreau să se întâmple acțiunea implicită (ceea ce înseamnă, evident, deschiderea unei noi pagini specificate în href atribut), deci hai să o prevenim:

    // src / controllers / employees_controller.js // apeluri de apel aici ... alegeți (e) e.preventDefault () console.log (this) console.log (e)

    e este obiectul evenimentului special care conține informații complete despre evenimentul declanșat. Rețineți, apropo, asta acest returnează controlerul în sine, nu un link individual! Pentru a avea acces la elementul care acționează ca ținta evenimentului, utilizați e.target.

    Reîncărcați pagina, faceți clic pe un element din listă și observați rezultatul!

    Lucrul cu statul

    Acum, când am angajat un angajat al evenimentului pentru clicuri pentru angajați, aș dori să stochez persoana selectată în mod curent. De ce? După păstrarea acestor informații, putem împiedica selectarea a doua oară a aceluiași angajat. Acest lucru ne va permite ulterior să evităm încărcarea acelorași informații de mai multe ori.

    Stimulul ne instruiește să persistăm statul în Data API, ceea ce pare destul de rezonabil. Mai întâi de toate, să oferim anumite ID-uri arbitrare pentru fiecare angajat care utilizează date id- atribut:

     
    • John Doe
    • angajați # alege "> Alice Smith
    • angajații # alege "> Will Brown
    • angajații # selectați "> Ann Grey

    Apoi, trebuie să luăm id-ul și să-l persistăm. Folosirea API-ului de date este foarte comună cu Stimulus, deci un mod special this.data obiect este furnizat pentru fiecare controler. Cu ajutorul acestuia, putem rula următoarele metode:

    • this.data.get ( 'nume'): obțineți valoarea prin atributul său.
    • this.data.set ('nume', valoare): setați valoarea sub un anumit atribut.
    • this.data.has ( 'nume'): verificați dacă atributul există (returnează o valoare booleană).

    Din păcate, aceste comenzi rapide nu sunt disponibile pentru obiectivele evenimentelor de tip clic, așa că trebuie să ne menținem getAttribute () în cazul lor:

     // src / controllers / employees_controller.js alege (e) e.preventDefault () this.data.set ("curent-angajat", e.target.getAttribute ('data-id'

    Dar putem face chiar mai bine prin crearea unui getter și a unui setter pentru angajatul curent:

     // src / controllers / employees_controller.js obține actualEmployee () return this.data.get ("curent-angajat") set curentEmployee (id) if (this.currentEmployee! == id) this.data.set ("angajat curent", id)

    Observați cum folosim this.currentEmployee getter și asigurați-vă că ID-ul furnizat nu este același cu cel deja stocat.

    Acum puteți să rescrieți alege() în modul următor:

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

    Reîncărcați pagina pentru a vă asigura că totul funcționează. Încă nu veți observa modificări vizuale, dar cu ajutorul instrumentului Inspector veți observa că ul are date-angajați-curent-angajat atribut cu o valoare care se modifică pe măsură ce dați clic pe link-uri. angajați parte din numele atributului este identificatorul controlerului și se adaugă automat.

    Acum, hai să mergem mai departe și să evidențiem angajatul ales în prezent.

    Folosind obiectivele

    Atunci când un angajat este selectat, aș dori să alocăm elementul corespunzător cu a .ales clasă. Desigur, s-ar fi putut rezolva această sarcină utilizând câteva funcții JS selector, dar Stimulus oferă o soluție mai clară.

    Faceți cunoștință cu obiectivele care vă permit să marcați unul sau mai multe elemente importante pe pagină. Aceste elemente pot fi accesate și manipulate cu ușurință după cum este necesar. Pentru a crea o țintă, adăugați a date-țintă atribut cu valoarea lui Controler. Target_name (care se numește a descriptorul țintă):

     
    • John Doe
    • angajați # alege "> Alice Smith
    • angajații # alege "> Will Brown
    • angajații # selectați "> Ann Grey

    Acum, stimulați Stimul despre aceste noi obiective definind o nouă valoare statică:

    // src / controllers / employees_controller.js clasa implicită pentru export extinde Controller static targets = ["employee"] // ...

    Cum accesăm acum obiectivele? Este la fel de simplu ca să spui this.employeeTarget (pentru a obține primul element) sau this.employeeTargets (pentru a obține toate elementele):

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

    Grozav! Cum ne pot ajuta aceste ținte acum? Ei bine, le putem folosi pentru a adăuga și elimina clasele CSS cu ușurință pe baza unor criterii:

     // src / controllers / employees_controller.js alegeți (e) e.preventDefault () this.currentEmployee = e.target.getAttribute ('data-id') this.employeeTargets.forEach ((el, i) .classList.toggle ("ales", acest.currentEmployee === el.getAttribute ("date-id"))

    Ideea este simplă: iteram peste o serie de ținte și pentru fiecare țintă comparați-o date id- la cea stocată sub this.currentEmployee. Dacă se potrivește, elementul este atribuit .ales clasă. În caz contrar, această clasă este eliminată. Puteți, de asemenea, extrage dacă (this.currentEmployee! == id) condiție de la setter și utilizați-l în ales() în loc de:

     // src / controllers / employees_controller.js alege (e) e.preventDefault () const id = e.target.getAttribute ('data-id') dacă (this.currentEmployee! == id) <--- this.currentEmployee = id this.employeeTargets.forEach((el, i) => el.classList.toggle ("ales", id === el.getAttribute ("date-id")))

    Arată bine! În cele din urmă, vom oferi un stil foarte simplu pentru .ales clasa în interiorul publice / main.css:

    .selectat font-weight: bold; text-decoration: nici unul; cursor: implicit; 

    Reîncărcați din nou pagina, faceți clic pe o persoană și asigurați-vă că persoana respectivă este evidențiată în mod corespunzător.

    Încărcarea datelor în mod asincron

    Următoarea noastră sarcină este de a încărca informații despre angajatul ales. Într-o aplicație din lumea reală, va trebui să configurați un furnizor de gazde, un back-end alimentat de ceva de genul Django sau Rails și un punct final API care să răspundă cu JSON care conține toate datele necesare. Dar vom face lucrurile un pic mai simple și să ne concentrăm doar pe partea clientului. Creaza un angajați director în cadrul public pliant. Apoi, adăugați patru fișiere care conțin date pentru angajați:

    1.json

    nume: "John Doe", "sex": "bărbat", "vârstă": "40", "poziție": "https : //burst.shopifycdn.com/photos/couple-in-love-at-sunset_373x.jpg " 

    2.json

    "nume": "Alice Smith", "sex": "feminin", "vârstă": "32", "post": "CTO", "salariu" : //burst.shopifycdn.com/photos/woman-listening-at-team-meeting_373x.jpg " 

    3.json

    "nume": "Will Brown", "gender": "bărbat", "vârstă": "30", " https://burst.shopifycdn.com/photos/casual-urban-menswear_373x.jpg " 

    4.json

    "nume": "Ann Gray", "sex": "femeie", "vârstă": "25", "poziție": "Junior Dev", "salariu" https://burst.shopifycdn.com/photos/woman-using-tablet_373x.jpg " 

    Toate fotografiile au fost preluate din fotografia gratuită de la Shopify numită Burst.

    Datele noastre sunt gata și așteaptă să fie încărcate! Pentru a face acest lucru, vom codifica separat loadInfoFor () metodă:

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

    Această metodă acceptă id-ul unui angajat și trimite o cerere de preluare asincronă către URI-ul dat. Există, de asemenea, două promisiuni: una pentru a aduce corpul și una pentru a afișa informațiile încărcate (vom adăuga metoda corespunzătoare într-un moment).

    Utilizați această nouă metodă înăuntru alege():

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

    Înainte de a codifica displayInfo () , avem nevoie de un element pentru a face efectiv datele. De ce să nu profităm din nou de ținte?

     

    Definiți obiectivul:

    // src / controllers / employees_controller.js clasa implicită pentru export extinde Controller static targets = ["employee", "info"] // ...

    Și acum îl utilizați pentru a afișa toate informațiile:

     // src / controllers / employees_controller.js displayInfo (raw_json) const info = JSON.parse (raw_json) const html = '
    • Nume: $ info.name
    • Sex: $ info.gender
    • Vârsta: $ info.age
    • Poziție: $ info.position
    • Salariu: $ info.salary
    'this.infoTarget.innerHTML = html

    Desigur, ești liber să angajezi un motor templating cum ar fi Handlebars, dar pentru acest caz simplu, care probabil ar fi depășit.

    Acum reîncărcați pagina și alegeți unul dintre angajați. Bio și imaginea lui ar trebui să fie încărcate aproape instantaneu, ceea ce înseamnă că aplicația noastră funcționează corect!

    Listă dinamică a angajaților

    Folosind abordarea descrisă mai sus, putem merge și mai mult și încărcați lista angajaților în zbor, mai degrabă decât să-l codificăm greu.

    Pregătiți datele în interiorul publice / employees.json fişier:

    "id": "1", "nume": "John Doe", "id": " ":" Will Brown ", " id ":" 4 "," name ":" Ann Grey "]

    Acum tweak publice / index.html fișier prin eliminarea listei codate greu și adăugarea a date-angajați-url atribut (rețineți că trebuie să furnizăm numele controlerului, în caz contrar API-ul de date nu va funcționa):

    Imediat ce controlorul este atașat la DOM, acesta trebuie să trimită o cerere de preluare pentru a construi o listă de angajați. Aceasta înseamnă că conectați() inversarea apelurilor este locul perfect pentru a face acest lucru:

     // src / controllers / employees_controller.js conectați () this.loadFrom (this.data.get ('url'), acestdisplayEmployees)

    Vă propun să creăm o generică mai generică loadFrom () care acceptă o adresă URL pentru a încărca date și pentru a efectua un apel invers pentru a face efectiv aceste date:

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

    Tweak alege() pentru a profita de loadFrom ():

     // src / controllers / employees_controller.js alege (e) e.preventDefault () const id = e.target.getAttribute ('data-id') dacă (this.currentEmployee! == id) this.loadFrom (' angajați / $ id .json ', acest.displayInfo) // <--- this.currentEmployee = id this.employeeTargets.forEach((el, i) => el.classList.toggle ("ales", id === el.getAttribute ("date-id")))

    displayInfo () poate fi simplificată, deoarece JSON este acum analizat chiar în interiorul loadFrom ():

     // src / controlorii / employees_controller.js displayInfo (info) const html = '
    • Nume: $ info.name
    • Sex: $ info.gender
    • Vârsta: $ info.age
    • Poziție: $ info.position
    • Salariu: $ info.salary
    'this.infoTarget.innerHTML = html

    Elimina loadInfoFor () și codul displayEmployees () metodă:

     // src / controllers / employees_controller.js displayImployees (angajați) let html = "
      "employees.forEach ((el) => html + = '
    • $ El.name
    • ') html + = "
    "this.element.innerHTML + = html

    Asta e! Acum redăm dinamic lista noastră de angajați pe baza datelor returnate de server.

    Concluzie

    În acest articol am abordat un cadru JavaScript modest numit Stimul. Am văzut cum să creați o nouă aplicație, să adăugați un controler cu o grămadă de apeluri și acțiuni și să introduceți evenimente și acțiuni. De asemenea, am efectuat încărcarea datelor asincrone cu ajutorul solicitărilor de preluare.

    În general, asta este pentru elementele de bază ale Stimulului - nu se așteaptă cu adevărat să ai cunoștințe arcane pentru a aplica aplicații web. Desigur, cadrul va avea probabil noi caracteristici în viitor, dar dezvoltatorii nu intenționează să îl transforme într-un monstru imens cu sute de instrumente. 

    Dacă doriți să găsiți mai multe exemple de utilizare a Stimulului, puteți consulta și acest manual mic. Și dacă sunteți în căutarea unor resurse suplimentare de JavaScript pentru a studia sau a utiliza în munca dvs., verificați ce avem disponibil în piața Envato. 

    Ți-a plăcut Stimulus? V-ar interesa să încercați să creați o aplicație în lumea reală, care să funcționeze în acest cadru? Împărtășiți-vă gândurile în comentariile!

    Ca întotdeauna, vă mulțumesc că ați rămas cu mine și până la următoarea dată.

    Cod