Med den växande komplexiteten av JavaScript-applikationer är ramverk ett absolut måste om du behöver träffa riktiga tidsfrister för världen. I den här artikeln ska vi titta på en ny ram kallad Spine Mobile som du kan använda för att skapa fantastiska mobila applikationer i CoffeeScript och HTML utan att offra den stora användarupplevelsen av inhemska appar.
Intresserad? Låt oss börja!
Spine är en lätt JavaScript MVC ram som du kan använda för att skapa fantastiska klient-sida webbapplikationer. Spine Mobile är en förlängning till Spine, speciellt utformad för att skapa mobila webbapplikationer med inbyggd känsla.
Uppgiftslistor och kontaktledare är ett dussin ett dussin, så låt oss göra något annorlunda i denna handledning och skapa en träningsinspelare. Användare kommer att kunna spela in träning, inklusive typ, tid och varaktighet. Då kommer vi att ha en enkel lista som visar alla inspelade träningspass. Det finns också mycket utrymme för vidareutveckling, som sociala funktioner och grafer.
Du kan checka ut en live-demo av den färdiga applikationen här, liksom alla exemplarets källkod på GitHub. Jag rekommenderar starkt att du följer med den här handledningen med källkoden, åtminstone initialt, eftersom det hjälper dig att komma igång om du är ny på Spine.
Om du någonsin behöver mer information om Spine Mobile, klicka sedan på det omfattande dokumentet eller adresslistan. För en kort introduktion till CoffeeScript, ta en titt på The Little Book on CoffeeScript.
Första sakerna först måste vi installera några npm-moduler, nämligen spine.app
och Fålla
. Den förra genererar Spine apps, medan den senare fungerar som en dependence manager. Om du inte har installerat dem redan måste du ladda ner Node och npm (båda sidorna har utmärkta installationsguider). Kör sedan:
npm installera -g spine.app hem
Nu för att faktiskt generera vår Spine Mobile-applikation:
ryggraden mobil ryggrad.workout cd spine.workout
Ta en bläddring runt katalogstrukturen och de ursprungliga filerna som Spine har skapat för dig.
$ ls -la .gitignore Procfile app css package.json public slug.json
De app
katalog är där all applikationens logik lever, till exempel dess modeller och controllers. De offentlig
katalog är bara full av statiska tillgångar, och är där vår ansökan i slutändan kommer att kompileras till. Det är offentlig
katalog som får fungerat som vår mobilapplikation.
Vår nya applikation har också vissa lokala beroenden (anges i package.json
), så låt oss fortsätta och installera dem nu:
npm installera .
Dessa kommer att hämta och installera lokala beroenden i en mapp som heter node_modules
(som inte borde vara i din källkontroll).
Det sista vi behöver göra är att köra Spineas utvecklingsserver, Hem.
hem server
Hem sammanställer CoffeeScript-filer, löser beroenden, sveper källan till CommonJS-moduler och sammanlänkar allt till en JavaScript-fil,
application.js
.
Nu när servern körs kan vi navigera till vår ursprungliga applikation på http: // localhost: 9294.
I MVC-ramar lagrar modellerna din applikations data och eventuell logik i samband med den data. Det är det - modellerna borde inte veta något annat om resten av din ansökan. De borde vara helt avkopplade.
Vår ansökan behöver spåra träningspass, registrera träningstyp, hur lång tid det tog och när det skedde.
Så låt oss gå vidare och skapa en ny modell genom att köra följande:
ryggradsmodell träning
Det kommer att generera en modell som heter: app / modeller / workout.coffee
. Låt oss öppna den filen och implementera vår Träna
modell genom att ersätta innehållet med detta:
Ryggrad = kräva ("ryggrad") klass Träning utökar Spine.Model @configure 'Workout', 'typ', 'minuter', 'date' @extend Spine.Model.Local belastning: -> super @date = nytt Datum .parse (@date)) validera: -> returnera "typ krävs" om inte @type returnera "minuter krävs" såvida inte @minutes returnerar "krävs datum" såvida inte @date module.exports = Workout
Ok, så det är mycket kod utan förklaring. låt oss borra ner i det och titta på detaljerna.
Först och främst skapar vi en Träna
klass som ärva från Spine.Model
, kallelse @configure ()
för att ange modellens namn och attribut:
klass träning utökar Spine.Model @configure "Workout", "typ", "minuter", "datum"
Än så länge är allt bra. Nu ska vi förlänga modellen med en namngiven modul Spine.Model.Local
. Detta säkerställer att modelldata kvarstår mellan sidladdningar med hjälp av HTML5 Local Storage.
@extend Spine.Model.Local
Nu nästa funktion, ladda()
, behöver lite förklaring. ladda()
kallas flera gånger internt i ryggraden, särskilt när poster är serialiserade och de-serialiserade. Vårt problem är att vi serialiserar posterna till JSON när de fortsätter dem med HTML5 Local Storage. JSON har emellertid inte en inbyggd "Date" -typ och serialiserar den bara till en sträng. Detta är ett problem, som vi vill datum
Attribut till att alltid vara ett JavaScript-datum. tvingande ladda()
, se till att datumattributet är en JavaScript Datum
, kommer att lösa detta problem.
ladda: -> super @date = nytt datum (Date.parse (@date))
Slutligen har vi en ganska okomplicerad bekräfta()
fungera. I ryggraden misslyckas en modellens validering om bekräfta()
funktionen returnerar någonting "truthy" - dvs en sträng. Här återvänder vi "typ som krävs"
om inte typ
attributet existerar. Med andra ord, vi validerar närvaron av typ
, minuter
och datum
attribut.
validera: -> returnera "typ krävs" om inte @type returnera "minuter krävs" om inte @minutes returnerar "datum krävs" såvida inte @date
Du märker att den sista linjen i modellen är en module.exports
uppdrag. Detta avslöjar Träna
klass, så andra filer kan kräva det. Spineapplikationer använder CommonJS-moduler, vilket kräver explicit modulmodul och export av egendom.
Den enda andra modellen vi behöver är a WorkoutType
modell. Detta kommer bara att bli en grundklass och innehåller en lista över giltiga träningstyper. Som tidigare måste vi generera modellen först:
ryggradsmodell workout_type
Och dess innehåll är en enkel klass, som innehåller en uppsättning giltiga träningstyper:
klass WorkoutType @types: ['running' jogging "walking" simning "tennis" squash "handstands" hoppar "aerobics" cykling "vikter"] @all: -> @types module.exports = WorkoutType
För mer information om modeller, se guide för Spine-modeller.
I Spineapplikationer är regulatorn limet mellan modeller och visningar. De lägger till händelsehörare i vyn, dra data ut i modellen och gör JavaScript-mallar.
Det viktigaste du behöver veta om Spineys kontroller är att de är alla scoped av ett enda element, el
fast egendom. Allt som en kontroller gör i sin livstid är scoped av det elementet; om det är att lägga till händelsehörare, svara på händelseåterkallelser, uppdatera elementets HTML eller dra ut formulärdata.
Spine Mobile applikationer har en global Skede
controller, som omfattar hela skärmen. Vår genererade ansökan innehåller redan en Skede
i app / index.coffee
, låt oss ersätta det med följande:
träningspass = krav ("kontroller / träning") klassen App sträcker sig Stage.Global Constructor: -> super # Instantiate our Workouts controller nya träningspassar # Setup några Ruttfyllor Spine.Route.setup (shim: true) @navigate '/ workouts' module.exports = App
Vår App
Stage kommer att vara den första controller som är instansierad och ansvarar för att ställa in resten av programmet. Du kan se, det kräver en ännu ej definierad controller som heter träning
, och instantiating träning
i klassen' konstruktör
fungera.
Med andra ord, när vår ansökan körs först, App
scenen kommer att bli instansierad. Det kommer i sin tur att göra vårt träning
controller, där all åtgärd kommer att vara. Du kan ignorera alla ruttsaker för tillfället.
Låt oss nu konfigurera det ovan nämnda träning
kontrollant:
ryggradskontroll träningspass
Den nya träning
styrenheten är placerad under app / controllers / workouts.coffee
. Den här regulatorn kommer att vara där det mesta av vår ansökan lever, så låt oss börja fylla i det genom att ersätta innehållet med följande:
Ryggrad = kräver ("ryggrad") Panel = kräver ("ryggradsmobile") # Kräv modeller Träning = kräva ("modeller / träning") WorkoutType = kräver ('modeller / träning_typ') # För att genomföras: förlänger paneltaket WorkoutsCreate utökar Panel class Workouts utökar Spine.Controller konstruktör: -> super # Vår ansökans två paneler @list = new WorkoutsList @create = new WorkoutsCreate # Setup några ruttsaker @rutiner / träningspass: (params) -> @ list.active (params) '/ träningspass / skapa': (params) -> @ create.active (params) # Hämta de första träningspasserna från det lokala lagret Workout.fetch () module.exports = Workouts
Låt oss nu borra ner i det och förklara vad som händer. För det första kräver vi vår applikations två modeller, Träna
och WorkoutType
:
# Kräv modeller Träning = kräva ('modeller / träning') WorkoutType = kräver ('modeller / träning_typ')
Sedan träning
Konstruktören ställer upp några Panel
s, ännu inte genomförda, och sedan några vägar som vi kan ignorera för tillfället. Till sist, Workout.fetch ()
kallas, hämtar alla lagrade data från lokal lagring.
Okej, nu har vi gjort en skälig del av inställningen med vår App
och träning
controllers, men nu kommer den roliga delen, panelerna.
Så vår ansökan har två Panel
controllers, en listvy och en skapa vy. Dessa två paneler hör till huvudfasen som säkerställer att de övergår in och ut ordentligt, bara visar en panel vid en viss tidpunkt.
Så låt oss först definiera vårt WorkoutsList
controller i app / controllers / workouts.coffee
, som du gissade det kommer att lista träningen. Lägg till följande kod efter fordra
uttalanden i workouts.coffee
, Innan träning
controller definition:
class WorkoutsList utökar Panel titel: "Workouts" konstruktör: -> super # Lägg till en knapp i rubriken @addButton ('Add', @add) # Bind modellen till vyn Workout.bind ('refresh change', @render) rendera: => # Hämta alla träningsrekord från modellen träningspass = Workout.all () # Lämna en mall med träningsfönstret mall = kräva ('visningar / träningspass') (träningspass) # Ersätt det aktuella elementets HTML med mallen @ html (mall) lägg till: -> # Navigera till "skapa" -kontrollen, med # swipe övergången till vänster @navigate ('/ workouts / create', trans: 'right')
Det första du märker är det WorkoutsList
sträcker Panel
, en klass definierad i spine.mobile
paket. Detta säkerställer att det ärverver Panel
s egenskaper, så applikationens Skede
kan arbeta med det.
Mallen använder ett bra bibliotek som heter Eco. Kolla in visningsguiden för mer information om sin syntax. Det är tillräckligt att säga, det är CoffeeScript-syntax, med hjälp av
notation för att göra mallvariabler till sidan.
Då har vi en fastighet som heter titel
. Detta är en valfri inställning, och kommer att vara titeln på vår panel.
I konstruktörfunktionen lägger vi till en knapp i panelhuvudet genom att ringa @addButton (titel, återuppringning)
. När man trycker på detta kommer det att påkalla klassen " Lägg till()
fungera.
Slutligen lägger vi till bindande till två händelser, refresh och Byta på Träna
modell. När modellen ändras, kommer dessa händelser att avfyras och vår återuppringning göra()
funktion påkallad. göra()
först drar ut alla Träna
poster från databasen, gör sedan en mall och ersätter panelens innehåll med resultatet.
Så denna mall fungerar bara som en funktion. Allt vi gör är att utföra den funktionen, som passerar i ett mallkontext, resultatet är det gjorda DOM-elementet. För mer information om hur det här fungerar, se visningsguiden, annars låt oss trycka på och definiera mallen.
I app / vyer
, skapa en mapp som heter pass
som kommer att innehålla alla våra mallar i samband med träning
kontrollant. Låt oss sedan skapa en fil under app / vyer / pass / index.jeco
som innehåller:
<%= @type %> för <%= @minutes %> mins på <%= @date.toDateString() %>
Mallen är .Jeco
förlängning är inte ett typsnitt, det är en jQuery-förlängning till Eco Templating-biblioteket som tillhandahålls av Hem. Det låter oss bland annat associera element med de ursprungliga malldata, vilket kommer att vara användbart senare.
Slutresultatet är en lista över träningspassar som ser ut så här:
Självklart, om du inte har skapat några träningspassar är listan tom. Vi kan programmera ett träningspass med hjälp av kommandoraden i Web Inspector-konsolen:
var träning = kräver ("modeller / träning"); Workout.create (typ: 'handstands', minuter: 5, datum: Date.now ());
Nu är den sista panelen som ska definieras WorkoutsCreate
, som kommer att innehålla formuläret för att skapa nya träningspass. Detta kommer att bli vår största controller, men det borde vara ganska enkelt när du är bekant med API och terminologi.
Den enda nya tillägget här är tillägget av en element
egenskap, vilket är en bekvämhjälp som matchar DOM-element till exempel variabler. I exemplet nedan är elementegenskapen inställd på 'form': 'form'
, som kartlägger
element till
@form
variabel.
class WorkoutsCreate utökar paneltitel: 'Add Workout' -element: 'form': 'form' constructor: -> super @addButton ('Back', @back) @addButton ('Create', @create) # Återställ visningen när detta panelen är aktiverad, # återställer formuläret @bind 'active', @render () render: -> # Hämta alla träningstyper typer = WorkoutType.all () # Återför mallen, ersätt HTML =html kräver / form ") (typer: typer) skapa: -> # Skapa nytt träningspass från formulärdatapost = Workout.create (@formData ()) # Navigera tillbaka till listan, om validering passerat @back () om objekt # Navigera tillbaka till listan tillbaka: -> @ form.blur () @navigate ('/ workouts', trans: 'left') # Retur formulärdata som ett objekt bokstavligt formData: -> type = @ form.find ('[name = val () minutes = parseInt (@ form.find ('[namn = minuter]') .val ()) date = @ form.find ('[namn = datum]') [0] .valueAsDate typ: typ, minuter: minuter, datum: datum
Så låt oss ta det ifrån varandra bit för bit. För det första, i WorkoutsCreate
konstruktör, vi lägger till två knappar till panelen, "Skapa" och "Tillbaka". Du kan noga gissa vad de ska göra.
Därefter är vi bindande till panelen aktiva händelse utlöses när panelen visas. När händelsen utlöses, kommer göra()
funktionen heter, ersätter kontrollelementets HTML med en återgiven mall. Genom att bifoga göra()
uppmaning till aktiva händelse, snarare än direkt i konstruktören, ser vi till att formuläret återställs när panelen navigeras till.
Den sista delen till panelen är skapa()
funktion, var vår Träna
posten kommer faktiskt att skapas. Vi använder formData ()
för att hämta användarens inmatning, passera den till Workout.create ()
.
Nu på att definiera app / vyer / pass / form.eco
mall som används i göra()
fungera:
Det är det för vår ansökan. Ge det en virvel och skapa några träningspass.
Det sista steget är att bygga vår program på disken och distribuera den. Vi kan göra det med Hem:
hembygge
Detta kommer att serialisera all din JavaScript / CoffeeScript till en fil (offentliga / application.js
) och alla dina CSS / Stylus (publika / application.css
). Du måste göra detta innan du trycker på din webbplats på en fjärrserver, så att den kan serveras statiskt.
Vi ska använda Heroku för att betjäna vår ansökan, ett bra alternativ för att servera Node.js och Rails-applikationer, och de har en generös fri plan. Du måste registrera dig för ett konto hos dem om du inte har en redan, samt installera Heroku-pärlan.
Nu behöver allt vi behöver för att distribuera vår app driva några Heroku-kommandon för att få vår applikation implementerad.
heroku skapa my-spine-app - stack cedar git add. git commit -m "first commit" git push heroku master heroku öppen
Voila! Du har nu en smidig mobil applikation som skrivs i CoffeeScript, HTML5 och CSS3. Vi har massor av möjligheter nu, som att pakka in PhoneGap för att komma åt telefonens API, anpassa teman för Android-telefoner eller lägga till offline-support.
Det kan kännas mycket att lära sig, men vi har faktiskt täckt det mesta av Spine API i denna handledning. Varför inte kolla in den omfattande dokumentationen, och lära dig lite mer om ramverket?
Jag är säker på att du har många frågor så tveka inte att fråga dig i kommentarerna och tack så mycket för att läsa! Annars, se till vår systerwebbplats, Mobiletuts +, för de bästa mobilfokuserade handledningarna på webben!