Er zijn veel JavaScript-frameworks die er zijn. Soms begin ik zelfs te denken dat ik de enige ben die nog geen raamwerk heeft gemaakt. Sommige oplossingen, zoals Angular, zijn groot en complex, terwijl sommige, zoals Backbone (dat meer een bibliotheek is dan een raamwerk), vrij eenvoudig zijn en slechts een handvol tools bieden om het ontwikkelingsproces te versnellen..
In het artikel van vandaag zou ik u een geheel nieuw kader willen voorstellen, genaamd Stimulus. Het werd gemaakt door een Basecamp-team onder leiding van David Heinemeier Hansson, een populaire ontwikkelaar die de vader was van Ruby on Rails.
Stimulus is een klein kader dat nooit bedoeld was om iets groots te worden. Het heeft zijn eigen filosofie en houding ten opzichte van de front-end ontwikkeling, die sommige programmeurs wel of niet leuk vinden. Stimulus is jong, maar versie 1 is al vrijgegeven, dus het moet veilig zijn om te gebruiken in de productie. Ik heb redelijk met dit kader gespeeld en vond de eenvoud en elegantie ervan heel goed. Hopelijk geniet je er ook van!
In deze post bespreken we de basisprincipes van Stimulus bij het maken van een toepassing van één pagina met asynchrone gegevensverzameling, gebeurtenissen, statuspersistentie en andere veelvoorkomende dingen.
De broncode is te vinden op GitHub.
Stimulus is gemaakt door ontwikkelaars bij Basecamp. In plaats van JavaScript-toepassingen met één pagina te maken, hebben ze besloten om een majestueuze monoliet te kiezen die mogelijk wordt gemaakt door Turbolinks en JavaScript. Deze JavaScript-code is geëvolueerd naar een klein en bescheiden raamwerk waarvoor u niet uren en uren hoeft te besteden aan het leren van al zijn concepten en voorbehouden.
Stimulus is meestal bedoeld om zichzelf te hechten aan bestaande DOM-elementen en op een of andere manier ermee te werken. Het is echter ook mogelijk om de inhoud dynamisch weer te geven. Al met al is dit raamwerk nogal verschillend van andere populaire oplossingen, omdat het bijvoorbeeld status in HTML blijft behouden, niet in JavaScript-objecten. Sommige ontwikkelaars vinden het misschien ongemakkelijk, maar geven Stimulus wel een kans, want het kan je echt verbazen.
Het raamwerk heeft slechts drie hoofdbegrippen die u moet onthouden, namelijk:
data-controller
Het attribuut "magic" verschijnt op de pagina. De documentatie legt uit dat dit kenmerk een brug is tussen HTML en JavaScript, net zoals klassen dienen als bruggen tussen HTML en CSS. Eén controller kan aan meerdere elementen worden gekoppeld en één element kan worden opgestart door meerdere controllers.data-actie
attributen.data-target
attributen.Zoals u ziet, kunt u met de hierboven genoemde kenmerken op een eenvoudige en natuurlijke manier inhoud scheiden van gedragslogica. Verderop in dit artikel zullen we al deze concepten in actie zien en opmerken hoe gemakkelijk het is om een HTML-document te lezen en te begrijpen wat er aan de hand is.
Stimulus kan eenvoudig worden geïnstalleerd als een NPM-pakket of direct worden geladen via de script
tag zoals uitgelegd in de documenten. Merk ook op dat dit framework standaard integreert met de Webpack-activabeheerder, die goodies zoals controller autoloading ondersteunt. Je bent vrij om elk ander build-systeem te gebruiken, maar in dit geval zal nog wat meer werk nodig zijn.
De snelste manier om met Stimulus aan de slag te gaan is door gebruik te maken van dit startersproject met een Express-webserver en Babel al aangesloten. Het hangt ook af van Yarn, dus zorg ervoor dat je het installeert. Om het project te klonen en alle afhankelijkheden te installeren, voert u het volgende uit:
git clone https://github.com/stimulusjs/stimulus-starter.git cd stimulus-starter garen installeren
Als u liever niets lokaal installeert, kunt u dit project op Glitch remixen en alle codering in uw browser uitvoeren.
Geweldig - we zijn er helemaal klaar voor en kunnen doorgaan naar de volgende sectie!
Stel dat we een kleine applicatie voor één pagina maken die een lijst met werknemers presenteert en informatie laadt zoals hun naam, foto, functie, salaris, geboortedatum, enz..
Laten we beginnen met de lijst met werknemers. Alle markeringen die we gaan schrijven, moeten in de public / index.html
bestand, dat al enkele zeer minimale HTML bevat. Voor nu zullen we al onze medewerkers op de volgende manier hard coderen:
Onze werknemers
- John Doe
- Alice Smith
- Will Brown
- Ann Gray
Leuk! Laten we nu een vleugje Stimulus-magie toevoegen.
Zoals de officiële documentatie uitlegt, is het belangrijkste doel van Stimulus om JavaScript-objecten (genaamd controllers) naar de DOM-elementen. De controllers brengen de pagina vervolgens tot leven. Als een conventie zouden de namen van controllers moeten eindigen met een _controller
postfix (wat heel bekend zou moeten zijn bij ontwikkelaars van Rails).
Er is een directory voor controllers al beschikbaar genaamd src / controllers
. Binnenin zul je een vinden hello_controller.js
bestand dat een lege klasse definieert:
import Controller uit "stimulus" export standaardklasse verlengt Controller
Laten we de naam van dit bestand wijzigen in employees_controller.js
. We hoeven dit niet specifiek te vereisen omdat controllers automatisch worden geladen dankzij de volgende coderegels in de src / index.js
het dossier:
const application = Application.start () const context = require.context ("./ controllers", true, /\.js$/) application.load (definitionsFromContext (context))
De volgende stap is om onze controller aan te sluiten op de DOM. Om dit te doen, stelt u a in data-controller
attribuut en wijs er een identifier aan toe (dat is werknemers
in ons geval):
Dat is het! De controller is nu verbonden met de DOM.
Een belangrijk ding om te weten over controllers is dat ze drie levenscyclus callbacks hebben die op specifieke voorwaarden worden geactiveerd:
initialiseren
: dit terugbellen gebeurt slechts één keer, wanneer de controller wordt geïnstantieerd.aansluiten
: vuurt telkens wanneer we de controller verbinden met het DOM-element. Aangezien een controller mogelijk is verbonden met meerdere elementen op de pagina, kan deze callback meerdere keren worden uitgevoerd.Loskoppelen
: zoals u waarschijnlijk wel hebt geraden, wordt deze callback uitgevoerd wanneer de controller de verbinding met het DOM-element verbreekt.Niets ingewikkelds, toch? Laten we profiteren van de initialiseren ()
en aansluiten()
callbacks om ervoor te zorgen dat onze controller echt werkt:
// src / controllers / employees_controller.js export standaardklasse verlengt Controller initialize () console.log ('Geïnitialiseerd') console.log (this) connect () console.log ('Connected') console.log ( deze)
Start de server vervolgens met:
garen start
Navigeren naar http: // localhost: 9000
. Open de console van uw browser en controleer of beide berichten worden weergegeven. Het betekent dat alles werkt zoals verwacht!
Het volgende Core Stimulus-concept is events. Gebeurtenissen worden gebruikt om te reageren op verschillende gebruikersacties op de pagina: klikken, zweven, scherpstellen, enz. Stimulus probeert geen fiets opnieuw uit te vinden en het gebeurtenissysteem is gebaseerd op generieke JS-evenementen.
Laten we bijvoorbeeld een klikgebeurtenis aan onze werknemers binden. Telkens wanneer dit gebeurt, zou ik het nog bestaande niet willen noemen Kiezen()
methode van de employees_controller
:
Waarschijnlijk kun je begrijpen wat er hier alleen aan de hand is.
data-actie
is het speciale kenmerk dat een gebeurtenis aan het element bindt en uitlegt welke actie moet worden aangeroepen.Klik
, natuurlijk, is de naam van het evenement.werknemers
is het ID van onze controller.Kiezen
is de naam van de methode die we graag willen bellen.Sinds Klik
is de meest voorkomende gebeurtenis, deze kan veilig worden weggelaten:
In dit geval, Klik
zal impliciet worden gebruikt.
Laten we vervolgens de code coderen Kiezen()
methode. Ik wil niet dat de standaardactie plaatsvindt (wat uiteraard een nieuwe pagina opent die is opgegeven in de href
kenmerk), dus laten we dit voorkomen:
// src / controllers / employees_controller.js // callbacks hier ... kies (e) e.preventDefault () console.log (this) console.log (e)
e
is het speciale gebeurtenisobject dat volledige informatie bevat over de geactiveerde gebeurtenis. Let op, trouwens deze
retourneert de controller zelf, geen individuele link! Als u toegang wilt krijgen tot het element dat fungeert als doelwit van de gebeurtenis, gebruikt u e.target
.
Laad de pagina opnieuw, klik op een lijstitem en observeer het resultaat!
Nu we een klikgebeurtenishandler aan de werknemers hebben gebonden, wil ik de momenteel gekozen persoon opslaan. Waarom? Nadat we deze informatie hebben opgeslagen, kunnen we voorkomen dat dezelfde medewerker de tweede keer wordt geselecteerd. Hierdoor kunnen we later voorkomen dat dezelfde informatie ook meerdere keren wordt geladen.
Stimulus geeft ons de opdracht de status-API in stand te houden, wat redelijk lijkt. Laten we allereerst enkele willekeurige id's opgeven voor elke medewerker die de data-id
attribuut:
Vervolgens moeten we het ID ophalen en dit blijven doen. Het gebruik van de Data-API komt heel vaak voor met Stimulus, dus een special Deze data
object is beschikbaar voor elke controller. Met zijn hulp kunnen we de volgende methoden gebruiken:
this.data.get ( 'name')
: haal de waarde op basis van zijn attribuut.this.data.set ('naam', waarde)
: stel de waarde in onder een attribuut.this.data.has ( 'name')
: controleer of het attribuut bestaat (geeft een Booleaanse waarde terug).Helaas zijn deze snelkoppelingen niet beschikbaar voor de doelen van de klikgebeurtenissen, dus we moeten ons houden aan getAttribute ()
in hun geval:
// src / controllers / employees_controller.js kiezen (e) e.preventDefault () this.data.set ("current-employee", e.target.getAttribute ('data-id'))
Maar we kunnen het nog beter doen door een getter en een setter te maken voor de huidige werknemer
:
// src / controllers / employees_controller.js krijgen currentEmployee () return this.data.get ("current-employee") stel currentEmployee (id) if (this.currentEmployee! == id) this.data.set in ("huidige werknemer", id)
Merk op hoe we de gebruiken this.currentEmployee
getter en ervoor te zorgen dat het opgegeven ID niet hetzelfde is als het reeds opgeslagen ID.
Nu mag je de Kiezen()
methode op de volgende manier:
// src / controllers / employees_controller.js kiezen (e) e.preventDefault () this.currentEmployee = e.target.getAttribute ('data-id')
Laad de pagina opnieuw om ervoor te zorgen dat alles nog steeds werkt. U zult nog geen visuele wijzigingen opmerken, maar met behulp van de Inspector-tool zult u merken dat het ul
heeft de data-werknemers-current-werknemer
attribuut met een waarde die verandert als je op de links klikt. De werknemers
deel in de naam van het attribuut is de identifier van de controller en wordt automatisch toegevoegd.
Laten we nu verder gaan en de momenteel gekozen werknemer benadrukken.
Wanneer een werknemer is geselecteerd, zou ik het overeenkomstige element willen toewijzen met een .uitgekozen
klasse. Natuurlijk kunnen we deze taak hebben opgelost door enkele JS-selectorfuncties te gebruiken, maar Stimulus biedt een nettere oplossing.
Ontmoet doelen, waarmee u een of meer belangrijke elementen op de pagina kunt markeren. Deze elementen kunnen vervolgens gemakkelijk worden geopend en gemanipuleerd wanneer nodig. Voeg een toe om een doel te creëren data-target
attribuut met de waarde van Controller. Target_name
(dat heet a doel descriptor):
Laat Stimulus nu over deze nieuwe doelen weten door een nieuwe statische waarde te definiëren:
// src / controllers / employees_controller.js export standaardklasse verlengt Controller static targets = ["employee"] // ...
Hoe krijgen we nu toegang tot de doelen? Het is zo simpel als zeggen this.employeeTarget
(om het eerste element te krijgen) of this.employeeTargets
(om alle elementen te krijgen):
// src / controllers / employees_controller.js kiezen (e) e.preventDefault () this.currentEmployee = e.target.getAttribute ('data-id') console.log (this.employeeTargets) console.log (this.employeeTarget )
Super goed! Hoe kunnen deze doelen ons nu helpen? Welnu, we kunnen ze gebruiken om op eenvoudige wijze CSS-klassen toe te voegen en te verwijderen op basis van een aantal criteria:
// src / controllers / employees_controller.js kiezen (e) e.preventDefault () this.currentEmployee = e.target.getAttribute ('data-id') this.employeeTargets.forEach ((el, i) => el .classList.toggle ("selected", this.currentEmployee === el.getAttribute ("data-id")))
Het idee is simpel: we herhalen verschillende doelen en vergelijken elk doel data-id
naar degene die is opgeslagen onder this.currentEmployee
. Als het overeenkomt, krijgt het element de .uitgekozen
klasse. Anders wordt deze klasse verwijderd. Je kunt ook het if (this.currentEmployee! == id)
conditie van de setter en gebruik deze in de gekozen ()
methode in plaats daarvan:
// src / controllers / employees_controller.js kies (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 ("selected", id === el.getAttribute ("data-id")))
Ziet er goed uit! Ten slotte zullen we een aantal zeer eenvoudige styling bieden voor de .uitgekozen
klasse binnen de public / main.css
:
.gekozen font-weight: bold; tekstdecoratie: geen; cursor: standaard;
Laad de pagina opnieuw opnieuw, klik op een persoon en zorg ervoor dat die persoon goed wordt gemarkeerd.
Onze volgende taak is om informatie over de gekozen werknemer te laden. In een toepassing in de echte wereld zou je een hostingprovider moeten opzetten, een back-end die wordt aangedreven door Django of Rails, en een API-eindpunt dat reageert met JSON met alle benodigde gegevens. Maar we gaan het een beetje eenvoudiger maken en ons alleen concentreren op de klant. Creëer een werknemers
map onder de openbaar
map. Voeg vervolgens vier bestanden met gegevens voor individuele werknemers toe:
1.json
"naam": "John Doe", "geslacht": "man", "leeftijd": "40", "positie": "CEO", "salaris": "$ 120.000 / jaar", "afbeelding": "https : //burst.shopifycdn.com/photos/couple-in-love-at-sunset_373x.jpg "
2.json
"name": "Alice Smith", "gender": "female", "age": "32", "position": "CTO", "salary": "$ 100.000 / year", "image": "https : //burst.shopifycdn.com/photos/woman-listening-at-team-meeting_373x.jpg "
3.json
"naam": "Will Brown", "geslacht": "mannelijk", "leeftijd": "30", "positie": "Tech Lead", "salaris": "$ 80.000 / jaar", "afbeelding": " https://burst.shopifycdn.com/photos/casual-urban-menswear_373x.jpg "
4.json
"name": "Ann Gray", "gender": "female", "age": "25", "position": "Junior Dev", "salary": "$ 20.000 / year", "image": " https://burst.shopifycdn.com/photos/woman-using-tablet_373x.jpg "
Alle foto's zijn genomen van de gratis stockfotografie door Shopify genaamd Burst.
Onze gegevens staan klaar om te worden geladen! Om dit te doen, coderen we een afzonderlijke code loadInfoFor ()
methode:
// src / controllers / employees_controller.js loadInfoFor (employee_id) fetch ('employees / $ employee_id .json') .then (response => response.text ()) .then (json => this.displayInfo ( json))
Deze methode accepteert de ID van een werknemer en verzendt een asynchrone ophaalopdracht naar de gegeven URI. Er zijn ook twee beloften: een om het lichaam op te halen en een ander om de geladen info weer te geven (we zullen de corresponderende methode in een moment toevoegen).
Gebruik deze nieuwe methode binnen Kiezen()
:
// src / controllers / employees_controller.js kiezen (e) e.preventDefault () const id = e.target.getAttribute ('data-id') if (this.currentEmployee! == id) this.loadInfoFor (id ) // ...
Voor het coderen van de displayInfo ()
methode hebben we een element nodig om de gegevens daadwerkelijk te renderen. Waarom maken we niet opnieuw gebruik van doelen??
Definieer het doel:
// src / controllers / employees_controller.js export standaardklasse verlengt Controller static targets = ["employee", "info"] // ...
En gebruik het nu om alle info weer te geven:
// src / controllers / employees_controller.js displayInfo (raw_json) const info = JSON.parse (raw_json) const html = '
Natuurlijk ben je vrij om een sjablonerende motor zoals Handlebars te gebruiken, maar voor dit eenvoudige geval zou dat waarschijnlijk overkill zijn.
Laad nu de pagina opnieuw en kies een van de werknemers. Zijn bio en afbeelding moeten vrijwel onmiddellijk worden geladen, wat betekent dat onze app naar behoren werkt!
Met behulp van de hierboven beschreven aanpak kunnen we zelfs verder gaan en de lijst met medewerkers direct laden in plaats van deze hard-coderen.
Bereid de gegevens in de public / employees.json
het dossier:
["id": "1", "name": "John Doe", "id": "2", "name": "Alice Smith", "id": "3", "name ":" Will Brown ", " id ":" 4 "," name ":" Ann Gray "]
Nu tweak public / index.html
bestand door de hardcoded lijst te verwijderen en een data-werknemers-url
kenmerk (merk op dat we de naam van de controller moeten vermelden, anders werkt de Data API niet):
Zodra de controller is aangesloten op de DOM, moet deze een ophaalopdracht verzenden om een lijst met werknemers samen te stellen. Het betekent dat de aansluiten()
callback is de perfecte plaats om dit te doen:
// src / controllers / employees_controller.js connect () this.loadFrom (this.data.get ('url'), this.displayEmployees)
Ik stel voor dat we meer generiek creëren loadFrom ()
methode die een URL accepteert om gegevens van te laden en een callback om deze gegevens daadwerkelijk weer te geven:
// src / controllers / employees_controller.js loadFrom (url, callback) fetch (url) .then (response => response.text ()) .then (json => callback.call (this, JSON.parse (json ))
Tweak de Kiezen()
methode om te profiteren van de loadFrom ()
:
// src / controllers / employees_controller.js kies (e) e.preventDefault () const id = e.target.getAttribute ('data-id') if (this.currentEmployee! == id) this.loadFrom (' werknemers / $ id .json ', this.displayInfo) // <--- this.currentEmployee = id this.employeeTargets.forEach((el, i) => el.classList.toggle ("selected", id === el.getAttribute ("data-id")))
displayInfo ()
kan ook worden vereenvoudigd, omdat JSON nu in de hele map wordt geparseerd loadFrom ()
:
// src / controllers / employees_controller.js displayInfo (info) const html = '
Verwijderen loadInfoFor ()
en codeer de displayEmployees ()
methode:
// src / controllers / employees_controller.js display Medewerkers (werknemers) let html = "
Dat is het! We geven nu onze lijst met werknemers dynamisch weer op basis van de gegevens die door de server worden geretourneerd.
In dit artikel hebben we een bescheiden JavaScript-framework behandeld, genaamd Stimulus. We hebben gezien hoe een nieuwe applicatie te maken, een controller met een heleboel callbacks en acties toe te voegen en evenementen en acties te introduceren. We hebben ook wat asynchrone gegevens geladen met behulp van ophaalopdrachten.
Al met al, dat is het voor de basisprincipes van Stimulus - het verwacht echt niet dat je wat mysterieuze kennis hebt om webtoepassingen te maken. Natuurlijk zal het raamwerk in de toekomst waarschijnlijk een aantal nieuwe functies hebben, maar de ontwikkelaars zijn niet van plan om er een enorm monster van te maken met honderden gereedschappen.
Als je meer voorbeelden wilt vinden van het gebruik van Stimulus, kijk dan ook eens naar dit kleine handboek. En als u op zoek bent naar aanvullende JavaScript-bronnen om te studeren of te gebruiken in uw werk, bekijk dan wat we beschikbaar hebben op de Envato-markt.
Vond je Stimulus leuk? Zou u geïnteresseerd zijn in het proberen om een real-world toepassing te creëren die mogelijk wordt gemaakt door dit framework? Deel uw mening in de commentaren!
Zoals altijd bedank ik je dat je bij me bent gebleven en tot de volgende keer.