In mijn inleidende artikel heb ik de basisbeginselen van het kader van Ember.js en de basisconcepten voor het bouwen van een Sintel-applicatie besproken. In dit vervolgartikel gaan we dieper in op specifieke delen van het framework om te begrijpen hoeveel van de functies samenwerken om de complexiteit van de ontwikkeling van één pagina-applicatie te abstraheren.
Ik heb eerder opgemerkt dat de gemakkelijkste manier om de bestanden te krijgen die je nodig hebt, is om naar de Github repo van Ember.js te gaan en de startkit naar beneden te halen, en dat klopt nog steeds. Deze boilerplate-kit bevat alle bestanden die je nodig hebt om je Ember-ervaring een kickstart te geven, dus download zeker van dit artikel.
Het interessante is dat de starterskit ook een goed voorbeeld is van een zeer eenvoudige Ember-app. Laten we er doorheen lopen om inzicht te krijgen in wat er aan de hand is. Merk op dat ik later dieper in specifieke gebieden ga graven, dus maak je geen zorgen als iets in dit gedeelte niet onmiddellijk zinvol is. Het is meer om u een goed begrip van de functionaliteit te geven voordat u in de details duikt.
Open index.html
in uw browser en ziet u het volgende:
Welkom bij Ember.js
Dit is niet erg spannend, weet ik, maar als je kijkt naar de code die dit heeft weergegeven, zul je zien dat het met heel weinig moeite is gedaan. Als we naar 'js / app.js' kijken, zien we de volgende code:
App = Ember.Application.create (); App.IndexRoute = Ember.Route.extend (setupController: function (controller) controller.set ('content', ['red', 'yellow', 'blue']););
Op het meest eenvoudige niveau heeft een Ember-app slechts één regel nodig om technisch gezien te worden beschouwd als een "app":
App = Ember.Application.create ();
Deze code stelt een instantie van het Ember-toepassingsobject in, samen met een standaard toepassingssjabloon, gebeurtenislisteners en toepassingsrouter. Neem een seconde en probeer te denken aan de code die u normaal zou moeten schrijven om een globale naamruimte te creëren, een client-side sjabloon, eventhandlers te binden voor wereldwijde gebruikersinteractie en geschiedenis & staatbeheer in uw code op te nemen. Ja, die ene regel doet dat allemaal. Maar laten we duidelijk zijn: ik zeg niet dat het al het werk voor je doet, maar het is het fundament waarop je voortbouwt, via een methode call.
De volgende set code stelt het gedrag van een route in, in dit geval, voor de main index.html
pagina:
App.IndexRoute = Ember.Route.extend (setupController: function (controller) controller.set ('content', ['red', 'yellow', 'blue']););
Houd er rekening mee dat routes worden gebruikt om de bronnen te beheren die aan een specifieke URL in de toepassing zijn gekoppeld, en waarmee Ember de verschillende staten van afzonderlijke pagina's kan volgen. De URL is de sleutel-ID die door Ember wordt gebruikt om te begrijpen welke applicatiestatus aan de gebruiker moet worden gepresenteerd.
In dit geval wordt de root-route standaard aangemaakt in Sintel. Ik had de route ook op deze manier expliciet kunnen definiëren:
App.Router.map (function () this.resource ('index', path: '/'); // Brengt ons naar "/");
Maar daar zorgt Ember voor mij voor de "root" van mijn applicatie. We zullen later routes in meer detail bespreken.
Ga terug naar de volgende code:
App.IndexRoute = Ember.Route.extend (setupController: function (controller) controller.set ('content', ['red', 'yellow', 'blue']););
In dit geval, wanneer een gebruiker de hoofdmap van de site raakt, zal Ember een controller instellen die een steekproefset met gegevens laadt met een semantische naam, genaamd inhoud
. Deze gegevens kunnen later in de app worden gebruikt, via deze controller met die naam. En dat is precies wat er gebeurt index.html
. Open het bestand en je zult het volgende vinden:
Dit is een client-side template voor Stuur. Houd er rekening mee dat Handlebars de sjabloonbibliotheek is voor Ember en van vitaal belang is voor het maken van gegevensgestuurde gebruikersinterfaces voor uw app. Ember gebruikt gegevensattributen om deze sjablonen te koppelen aan de controllers die uw gegevens beheren, ongeacht of ze zijn opgegeven via een route of als een stand-alone controller.
In mijn laatste artikel vermeldde ik dat naamgevingsconventies belangrijk zijn in Sintel en dat ze het verbinden van functies gemakkelijk maken. Als u de sjablooncode bekijkt, ziet u dat de naam van de sjabloon (opgegeven via de data-template-naam attribuut) is "index". Dit is doelgericht en is bedoeld om het gemakkelijk te maken om verbinding te maken met de controller die is opgegeven in de route met dezelfde naam. Als we de routecode opnieuw bekijken, ziet u dat deze "IndexRoute" wordt genoemd en binnenin een controller met gegevens die worden ingesteld:
App.IndexRoute = Ember.Route.extend (setupController: function (controller) controller.set ('content', ['red', 'yellow', 'blue']););
De controller stelt een gegevensbron in met de naam "inhoud" en laadt deze met een reeks tekenreeksen voor de kleuren. Kortom, de array is uw model en de controller wordt gebruikt om die kenmerken van het model bloot te leggen.
Dankzij de naamgevingsconventies kan Ember de bronnen van deze route (bijvoorbeeld de controller met gegevens) koppelen aan de sjabloon die met dezelfde naam is opgegeven. Hierdoor krijgt de sjabloon toegang tot de gegevens die door de controller worden weergegeven, zodat deze deze kan gebruiken met behulp van de instructies van Handlebar. Vanaf daar worden de items in de array doorgelust met behulp van Handlebars ' elk richtlijn en specificeert de alias model- die naar de gegevensbron verwijst:
#each item in model
Om preciezer te zijn, de gegevens worden ingevuld in dynamisch gemaakte lijstitems en genereren zo de markup voor u tijdens de vlucht. Dat is het mooie aan client-side templates.
Ik denk dat deze basisapp duidelijk maakt hoe Ember veel dingen voor je abstraheert. Het is een beetje zwarte magie en het is niet altijd gemakkelijk om te begrijpen hoe de dingen werken. Dat is me echt overkomen en het klikte in het begin niet helemaal. Zodra je de verbanden tussen de verschillende componenten van het raamwerk begint te begrijpen, begint het logischer te worden. Laten we van de grond af beginnen om dit beter te begrijpen.
Ik heb kort het toepassingsobject van de Sintel aangeraakt en het feit dat dit de basis vormt voor uw toepassing. De Ember-gidsen doen uitstekend werk in het specifiek schetsen van wat een Euber-toepassingsobject doet:
App.PostsView
en App.PostsController
). Dit helpt voorkomen dat de wereldwijde scope wordt vervuild. Dus deze simpele verklaring:
App = Ember.Application.create ();
bedraad een hele stapel basisstukken waar je toepassing van afhankelijk is. Het is belangrijk om dat op te merken App is geen sleutelwoord in Sintel. Het is een normale globale variabele die u gebruikt om de naamruimte te definiëren en die elke geldige variabelenaam kan zijn. Van wat ik echter heb gezien, de naam van de variabele, App, is een veelgebruikte conventie in de meeste Ember-apps en wordt eigenlijk aanbevolen om het kopiëren en plakken van een groot deel van de voorbeeldcode die in de community wordt gemaakt, gemakkelijker te maken.
Als je bovenstaande lijst gebruikt, is wat Ember doet, via die ene regel, in essentie deze code automatisch voor je aan het maken achter de schermen:
// Maak de toepassingsnaamruimte App = Ember.Application.create (); // Maak de globale router om de paginastatus via URL's te beheren App.Router.map (function () ); // Maak de standaardtoepassingsroute om de staatseigenschappen op toepassingsniveau in te stellen App.ApplicationRoute = Ember.Route.extend (); // Maak de standaard toepassingssjabloon
Hoewel de starterkit dus niet expliciet een router, route of sjabloon met toepassingsbereik heeft gedefinieerd, heeft Ember ervoor gezorgd dat ze zijn gemaakt en beschikbaar zijn, zodat de basis van uw app voor u is ingesteld en beschikbaar is. Het is beslist goed om de code expliciet te maken. U kunt dit zelfs doen als u gegevens wilt doorgeven of kenmerken wilt instellen voor uw instantie van het toepassingsobject.
Nu vraagt u zich wellicht af hoe deze 'toepassingssjabloon' automatisch wordt weergegeven en waarom u deze niet ziet index.html
. Dat komt omdat het optioneel is om expliciet de toepassing sjabloon. Als het in de opmaak staat, zal Ember het onmiddellijk weergeven. Anders gaat het door met het verwerken van andere delen van uw applicatie zoals normaal. De typische use-case voor de toepassing sjabloon definieert globale, applicatie-brede elementen van de gebruikersinterface, zoals kop- en voetteksten.
Het definiëren van de toepassing sjabloon gebruikt dezelfde stijlsyntaxis als elke andere sjabloon, behalve met een klein verschil: de sjabloonnaam hoeft niet te worden opgegeven. Dus je sjabloon zo definiëren:
of dit:
geeft u exact dezelfde resultaten. Ember interpreteert een sjabloon zonder nummer data-template-naam als de toepassingssjabloon en zal deze automatisch weergeven wanneer de toepassing start.
Als je update index.html
door deze code toe te voegen:
U ziet nu dat de inhoud van de header-tag bovenaan de inhoud van de indexsjabloon wordt weergegeven. Het stuur Uitlaat richtlijn dient als een tijdelijke aanduiding in de toepassing sjabloon, waardoor Ember andere sjablonen erin kan injecteren (die als een soort verpakking dienen) en u wereldwijde UI-functies zoals kop- en voetteksten kunt bieden die uw inhoud en functionaliteit omringen. Door de toepassing sjabloon naar index.html
, je hebt Sintel opdracht gegeven om:
Uitlaat
richtlijninhoudsopgave
sjabloon Een belangrijke afhaalmogelijkheid is dat we slechts één sjabloon hebben toegevoegd (toepassing), en Sintel zorgde meteen voor de rest. Het zijn deze functiebindingen die Ember.js zo krachtig maken om mee te werken.
Routering is misschien wel het moeilijkste concept om te begrijpen in Sintel, dus ik zal mijn best doen om het op te splitsen tot hanteerbare stappen. Als een gebruiker uw applicatie navigeert, moet er een methode zijn om de staat van de verschillende onderdelen die de gebruiker bezoekt te beheren. Dat is waar de router- en locatiespecifieke routes van de toepassing binnenkomen.
Het Ember routerobject is wat dit beheert door het gebruik van routes die de benodigde resources voor specificatie locaties identificeren. Ik beschouw de router graag als een verkeersagent die auto's (gebruikers) naar verschillende straten (URL's en routes) leidt. De routes zelf zijn gekoppeld aan specifieke URL's en wanneer de URL wordt geopend, worden de routesbronnen beschikbaar gesteld.
Kijken naar js / app.js
nogmaals, je zult merken dat er een route is gemaakt voor de root-pagina (inhoudsopgave):
App.IndexRoute = Ember.Route.extend (setupController: function (controller) controller.set ('content', ['red', 'yellow', 'blue']););
Er is echter geen routerinstantie. Onthoud dat Ember standaard een router zal maken als u er geen opgeeft. Het zal ook een standaard route-invoer creëren voor de root van de applicatie die er ongeveer zo uitziet:
App.Router.map (function () this.resource ('index', path: '/'););
Dit vertelt aan Ember dat wanneer de root van de toepassing wordt geraakt, deze de bronnen van een geroepen routeobject moet laden IndexRoute als het beschikbaar is. Dit is de reden waarom, ondanks dat er geen routerinstantie is gedeclareerd, de toepassing nog steeds wordt uitgevoerd. Sintel weet intern dat de wortelroute moet worden genoemd IndexRoute, zal er naar op zoek gaan en zijn bronnen overeenkomstig laden. In dit geval wordt een controller gemaakt die gegevens bevat die in de indexsjabloon moeten worden gebruikt.
Aangezien URL's de sleutel-ID's zijn die door Ember worden gebruikt om de status van uw toepassing te beheren, zal elk van hen over het algemeen een eigen routehandler hebben opgegeven als bronnen voor dat gedeelte van de app moeten worden geladen. Dit is wat ik bedoel; stel dat je een app hebt met drie secties:
In de meeste gevallen heeft elk van deze secties zijn eigen unieke bronnen die moeten worden geladen (bijvoorbeeld: gegevens of afbeeldingen). Dus je zou routehandlers maken met behulp van de middelen () methode binnen het applicatie object van de applicatie-router van Ember zoals dit:
App.Router.map (function () this.resource ('accounts'); this.resource ('profiles'); this.resource ('gallery'););
Hierdoor kan Ember de structuur van de applicatie begrijpen en resources beheren. De routesdefinities zullen correleren met individuele route-objectinstances die feitelijk de zwaar opheffend achtige opstelling of interfacing van controllers doen:
App.GalleryRoute = Ember.Route.extend (setupController: function (controller) controller.set ('content', ['pic-1.png', 'pic-2.png', 'pic-3.png' ]););
Dus in het bovenstaande voorbeeld, wanneer een gebruiker '/ gallery' bezoekt, maakt Ember.js het GalleryRoute-routeobject instantaan, stelt een controller in met gegevens en geeft de galerij sjabloon. Nogmaals, dit is waarom naamgevingsconventies zo belangrijk zijn in Sintel.
Uw toepassing kan ook geneste URL's bevatten, zoals / Account / new
Voor deze instanties kunt u Ember-bronnen definiëren waarmee u routes samen kunt groeperen, zoals:
App.Router.map (function () this.resource ('accounts', function () this.route ('new');););
In dit voorbeeld hebben we de middelen ()
methode om de routes samen te groeperen en de route()
methode om de routes binnen de groep te definiëren. De algemene vuistregel is om te gebruiken middelen ()
voor zelfstandige naamwoorden (Accounts en Account zouden beide bronnen zijn, zelfs als ze zijn genest) en route()
voor modifiers: (werkwoorden zoals nieuwe
en Bewerk
of bijvoeglijke naamwoorden zoals favorieten
en starred
).
Naast het groeperen van de routes, bouwt Ember interne verwijzingen naar de controllers, routes en sjablonen voor elk van de gespecificeerde groepsroutes. Dit is hoe het eruit zou zien (en opnieuw raakt het aan de naamgevingsconventies van Ember):
"/ Accounts":
"/ Accounts / new":
Wanneer een gebruiker '/ accounts / new' bezoekt, is er een beetje een bovenliggend / kind- of hoofd- / detailscenario dat optreedt. Ember zal eerst zorgen dat de middelen voor rekeningen zijn beschikbaar en geven de rekeningen sjabloon (dit is het meesterstuk ervan). Daarna zal het een follow-up uitvoeren en hetzelfde doen voor "/ accounts / new", resources instellen en de accounts.new sjabloon.
Houd er rekening mee dat bronnen ook kunnen worden genest voor veel diepere URL-structuren, zoals deze:
App.Router.map (function () this.resource ('accounts', function () this.route ('new'); this.resource ('pictures', function () this.route ('add' ););););
Ik heb veel materiaal in deze post behandeld. Hopelijk heeft het een aantal aspecten vereenvoudigd van hoe een Sintel-applicatie functioneert en hoe routes werken.
We zijn nog steeds niet klaar. In het volgende bericht duik ik in de functies van Ember om gegevens terug te trekken en beschikbaar te maken met je app. Dit is waar modellen en controllers binnenkomen, dus we zullen ons concentreren op het begrijpen hoe de twee samenwerken.