Komma igång med Spine Mobile

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!


Vad exakt är ryggrad?

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.


Steg 1: Inställning

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.


Steg 2: Modeller

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.

WorkoutType-modell

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.


Steg 3: Huvudkontroller

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 Panels, ä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.


Steg 4: Lista övningar

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 Panels 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 BytaTrä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 ());

Steg 5: Skapa nya träningspass

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.


Steg 6: Bygg och distribuera

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.


Nästa steg

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!