Med den voksende kompleksiteten av JavaScript-applikasjoner, er rammeverk et absolutt must hvis du trenger å møte virkelige verdensfrister. I denne artikkelen skal vi se på et nytt rammeverk som heter Spine Mobile, som du kan bruke til å lage flotte mobile applikasjoner i CoffeeScript og HTML, uten å ofre den store brukeropplevelsen av innfødte apps.
Interessert? La oss komme i gang!
Spine er en lett JavaScript MVC rammeverk som du kan bruke til å lage flotte web-applikasjoner på klientsiden. Spine Mobile er en forlengelse til Spine, spesielt utviklet for å skape innfødte mobile webapplikasjoner.
Oppgavelister og kontaktledere er et dime et dusin, så la oss gjøre noe annerledes i denne opplæringen og opprette en treningsopptaker. Brukere skal kunne registrere treningsøkter, inkludert deres type, tid og varighet. Da skal vi ha en enkel liste som viser alle innspilte treningsøkter. Det er også mye mulighet for videreutvikling, for eksempel sosiale funksjoner og grafer.
Du kan sjekke en live demo av det ferdige programmet her, samt alle eksempler kildekoden på GitHub. Jeg anbefaler at du følger denne opplæringen ved hjelp av kildekoden, i hvert fall i utgangspunktet, da det hjelper deg å komme i gang hvis du er ny til Spine.
Hvis du noen gang trenger mer informasjon om Spine Mobile, så slå opp omfattende dokument eller adresseliste. For en kort introduksjon til CoffeeScript, ta en titt på The Little Book on CoffeeScript.
Første ting først, vi trenger å installere noen npm moduler, nemlig spine.app
og hem
. Den førstnevnte genererer Spine apps, mens sistnevnte fungerer som en dependence manager. Hvis du ikke har installert dem allerede, må du laste ned Node og npm (begge nettstedene har gode installasjonsguider). Kjør deretter:
npm installer -g spine.app hem
Nå for å faktisk generere vår Spine Mobile-applikasjon:
ryggraden mobil ryggraden.workout cd spine.workout
Ta en titt rundt katalogstrukturen og de første filene som Spine har skapt for deg.
$ ls -la .gitignore Procfile app css package.json offentlig slug.json
De app
katalog er hvor alle programmets logikk lever, for eksempel modeller og kontroller. De offentlig
katalogen er bare full av statiske eiendeler, og er der søknaden vår til slutt blir kompilert til. Det er offentlig
katalog som blir servert som mobilapplikasjon.
Vår nye applikasjon har også noen lokale avhengigheter (spesifisert i package.json
), så la oss gå videre og installere de nå:
npm installasjon .
Disse vil laste ned og installere de lokale avhengighetene i en mappe som heter node_modules
(som ikke burde være i kildekontrollen din).
Det siste vi trenger å gjøre er å drive Spines utviklingsserver, Hem.
hem server
Hem kompiler CoffeeScript-filer, løser avhengigheter, bryter kilde inn i CommonJS-moduler og sammenkaller alt til en JavaScript-fil,
application.js
.
Nå som serveren kjører, kan vi navigere til vår første applikasjon på http: // localhost: 9294.
I MVC-rammene lagrer modellene søknadens data og enhver logikk knyttet til dataene. Det er det - modellene burde ikke vite noe annet om resten av søknaden din; De skal være helt dekoblet.
Vår søknad må spore treningsøkter, registrerer type treningsøkt, hvor lang tid det tok, og når det skjedde.
Så la oss gå videre og lage en ny modell ved å kjøre følgende:
ryggraden modell trening
Det vil generere en modell som heter: app / modeller / workout.coffee
. La oss åpne den filen og implementere vår Trene
modell ved å erstatte innholdet med dette:
Ryggraden = krever ('ryggrad') klasse Trening utvider Spine.Model @configure 'Trening', 'type', 'minutter', 'dato' @extend Spine.Model.Local belastning: -> super @date = nytt Dato .parse (@date)) validere: -> returnere "type kreves" med mindre @type returnerer "minutter kreves" med mindre @minutes return "dato kreves" med mindre @date module.exports = Workout
Ok, så det er mye kode uten noen forklaring; la oss bore ned i det og se på detaljene.
For det første skaper vi en Trene
klasse arve fra Spine.Model
, ringer @configure ()
å angi modellens navn og attributter:
klassen trening utvider spine.Model @configure 'trening', 'type', 'minutter', 'dato'
Så langt så bra. Nå skal vi utvide modellen med en modul som heter Spine.Model.Local
. Dette sikrer at modelldataene er vedvarende mellom sideopplasting ved hjelp av HTML5 Local Storage.
@extend Spine.Model.Local
Nå neste funksjon, laste()
, trenger litt forklaring. laste()
blir kalt flere ganger internt i ryggraden, spesielt når poster er serialisert og de-serialisert. Problemet vårt er at vi serialiserer postene til JSON når de vedvarer dem med HTML5 Local Storage. JSON har imidlertid ikke en innfødt "Dato" -type, og serialiserer den bare til en streng. Dette er et problem, som vi vil Dato
attributt til å alltid være en JavaScript-dato. Overstyre laste()
, sørg for datatributtet er et JavaScript Dato
, vil løse dette problemet.
last: -> super @date = nytt Dato (Date.parse (@date))
Til slutt har vi ganske rettferdig validere()
funksjon. I ryggraden mislykkes en modells validering hvis validere()
funksjonen returnerer noe "truthy" - det vil si en streng. Her kommer vi tilbake "type kreves"
med mindre type
attributtet eksisterer. Med andre ord, vi validerer tilstedeværelsen av type
, minutter
og Dato
egenskaper.
validere: -> retur 'type kreves' med mindre @type returnerer 'minutter kreves' med mindre @minutes returnerer 'dato kreves' med mindre @date
Du vil merke at den endelige linjen i modellen er en module.exports
oppdrag. Dette avslører Trene
klasse, så andre filer kan kreve det. Spineapplikasjoner bruker CommonJS-moduler, som krever eksplisitt moduler som krever og eksporterer eiendom.
Den eneste andre modellen vi trenger er a WorkoutType
modell. Dette skal bare være en grunnklass, og inneholder en liste over gyldige treningsformer. Som før må vi først generere modellen:
ryggradsmodell treningstype
Og så er innholdet en enkel klasse, som inneholder en rekke gyldige treningsformer:
class WorkoutType @types: ['running' jogging 'walking' svømming "tennis" squash "handstands" hopper "aerobic" sykling "vekter '] @all: -> @types module.exports = WorkoutType
For mer informasjon om modeller, se Spine-modeller-veiledningen.
I Spineapplikasjoner er regulatorer limet mellom modeller og visninger. De legger til hendelselyttere i visningen, drar data ut av modellen og gjør JavaScript-maler.
Nøkkelen du trenger å vite om Spine er kontroller, er at de er alle scoped av et enkelt element, den el
eiendom. Alt som en kontroller gjør i sin levetid er scoped av det elementet; om det er å legge til hendelseslyttere, svare på event-tilbakeringinger, oppdatering av elementets HTML, eller å trekke ut skjemadata.
Spine Mobile applikasjoner har en global Scene
kontrolleren, som omfatter hele skjermen. Vår genererte søknad inneholder allerede a Scene
i app / index.coffee
, la oss erstatte det med følgende:
kreves ('spine.mobile') Trening = krever ('kontroller / trening') klasse App utvider Stage.Global constructor: -> super # Instantiate our Workouts kontroller nye treningsøktene # Oppsett noen Rute ting Spine.Route.setup (shim: true) @navigate '/ workouts' module.exports = App
Våre app
Stage skal være den første kontrolleren som er opprettet, og har ansvaret for å sette opp resten av applikasjonen. Du kan se, det krever en som ubestemt regulator som heter økter
, og instantiating økter
i klassen' konstruktør
funksjon.
Med andre ord, når søknaden vår først kjører, app
scenen kommer til å bli instantiated. Det vil igjen skape vår økter
kontrolleren, hvor all handlingen skal være. Du kan ignorere alle rutepostene for tiden.
La oss nå sette opp ovennevnte økter
kontrolleren:
ryggraden kontroller treningsøkter
Den nye økter
kontrolleren er plassert under app / kontrollere / workouts.coffee
. Denne kontrolleren skal være der det meste av vår søknad lever, så la oss begynne å fylle ut det ved å erstatte innholdet med følgende:
Spine = krever ('ryggrad') Panel = krever ('spine.mobile') # Krever modeller Trening = krever ('modeller / trening') WorkoutType = krever ('modeller / workout_type') # For å bli implementert: utvider panel klassen treningsøktene utvide panelet klassen trening øker spine.controller konstruktør: -> super # vår søknad er to paneler @list = new workoutsliste @create = new workoutscreate # sette opp noen rute ting @rutiner / trening: (Params) -> @ list.active (params) '/ workouts / create': (params) -> @ create.active (params) # Hent de første treningene fra lokal lagring Workout.fetch () module.exports = Treningsøkter
Igjen, la oss bore ned i det og forklare hva som skjer. For det første krever vi programmets to modeller, Trene
og WorkoutType
:
# Krev modeller Trening = krever ('modeller / trening') WorkoutType = krever ('modeller / workout_type')
Deretter økter
Konstruktør setter opp noen Panel
s, som ennå ikke er gjennomført, og så noen ruter som vi kan ignorere for tiden. Endelig, Workout.fetch ()
blir kalt, henter alle lagrede data fra lokal lagring.
Ok, nå har vi gjort en god del å sette opp med vår app
og økter
kontrollere, men nå kommer den morsomme delen, panelene.
Så vår søknad har to Panel
kontroller, en listevisning og en opprettelse av visning. Disse to panelene tilhører hovedtrinnet som sikrer at de overgår inn og ut på riktig måte, kun viser ett panel til enhver tid.
Så la oss først definere vår WorkoutsList
kontrolleren i app / kontrollere / workouts.coffee
, som du gjettet det, vil liste opp treningene. Legg til følgende kode etter krever
uttalelser i workouts.coffee
, før økter
kontroller definisjon:
klassen TreningslisteList utvider Panel tittel: 'Workouts' constructor: -> super # Legg til en knapp i overskriften @addButton ('Add', @add) # Bind modellen til visningen Workout.bind ('refresh change', @render) gjengivelse: => # Hent alle treningsoppføringer fra modellen treningsøkter = Workout.all () # Gi en mal med treningsprogrammalen = kreve ('visninger / treningsøkter') (treningsøkter) # Erstatt gjeldende elementets HTML med malen @ html (template) add: -> # Naviger til 'create' kontrolleren, med en # swipe overgang ut til venstre @navigate ('/ workouts / create', trans: 'right')
Det første du vil merke er det WorkoutsList
strekker Panel
, en klasse definert i spine.mobile
pakke. Dette sikrer at den arver Panel
s egenskaper, så søknaden er Scene
kan jobbe med det.
Malen bruker et flott bibliotek kalt Eco. Sjekk ut visningsveiledningen for mer informasjon om sin syntaks. Tilstrekkelig å si, det er CoffeeScript syntaks, ved hjelp av
notasjon for å gjengi malvariabler til siden.
Da har vi en eiendom som heter tittel
. Dette er en valgfri innstilling, og vil bli tittelen på panelet vårt.
I konstruktørfunksjonen legger vi til en knapp i paneloverskriften ved å ringe @addButton (tittel, tilbakeringing)
. Når tappet, vil dette påkalle klassen ' Legg til()
funksjon.
Til slutt legger vi til bindende til to hendelser, forfriske og endring på Trene
modell. Når modellen endres, blir disse hendelsene sparket, og vår tilbakeringing render ()
funksjon påkalt. render ()
Først trekker du ut alle Trene
poster fra databasen, gjøres deretter en mal, erstatter panelets innhold med resultatet.
Så denne malen fungerer bare som en funksjon. Alt vi gjør er å utføre den funksjonen, og passere i en malekontekst, resultatet er det gjengitte DOM-elementet. For mer informasjon om hvordan dette fungerer, vennligst se visningsveiledningen, ellers la oss trykke på og definere mal.
I app / visninger
, lag en mappe som heter treningsøkter
som vil inneholde alle våre maler knyttet til økter
kontrolleren. La oss lage en fil under app / visninger / trening / index.jeco
inneholder:
<%= @type %> til <%= @minutes %> mins på <%= @date.toDateString() %>
Malen er .Jeco
utvidelsen er ikke en skrivefeil, det er en jQuery-utvidelse til Eco templating-biblioteket fra Hem. Blant annet gjør det oss mulig å knytte elementer med de opprinnelige maldataene, som vil være nyttige senere.
Sluttresultatet er en liste over treningsøkter som ser slik ut:
Selvfølgelig, hvis du ikke har opprettet noen treningsøkter, vil listen bli tom. Vi kan opprette en treningsøkt programmatisk, ved hjelp av kommandolinjen inne i Web Inspector-konsollen:
var trening = krever ('modeller / trening'); Workout.create (type: 'handstands', minutter: 5, dato: Date.now ());
Nå er det siste panelet som skal defineres WorkoutsCreate
, som vil inneholde skjemaet for å skape nye treningsøkter. Dette kommer til å være vår største kontroller, men det bør være ganske grei nå, da du er kjent med API og terminologi.
Det eneste nye tillegget her er tillegg av en elementer
Egenskapen, som er en praktisk hjelper til å matche DOM-elementer til forekomstvariabler. I eksemplet nedenfor er elementegenskapen satt til 'form': 'form'
, som kartlegger
element til
@form
variabel.
klassekompetanseKreate utvides Panel tittel: 'Legg til trening' elementer: 'form': 'form' constructor: -> super @addButton ('Back', @back) @addButton ('Create', @create) # Gjenta visningen når dette panelet er aktivert, # tilbakestille skjemaet @bind 'active', @render () gjengivelse: -> # Hent alle treningsmodelltyper = WorkoutType.all () # Tilbakestill malen, erstatte HTML @html krever ('visninger / treningsøkter / form ") (typer: typer) opprette: -> # Opprett ny trening fra formdataelement = Workout.create (@formData ()) # Naviger tilbake til listen, hvis validering passert @back () hvis element # Naviger tilbake til listen tilbake: -> @ form.blur () @navigate ('/ workouts', trans: 'left') # Tilbakestill skjemodata som en objekts bokstavelig formData: -> type = @ form.find ('[name = val () minutes = parseInt (@ form.find ('[navn = minutter]') .val ()) date = @ form.find ('[navn = dato]') [0] .valueAsDate type: type, minutter: minutter, dato: dato
Så la oss ta det fra hverandre. For det første, i WorkoutsCreate
Konstruktør, vi legger til to knapper til panelet, "Opprett" og "Tilbake". Du kan sikkert gjette hva disse skal gjøre.
Deretter er vi bindende til panelets aktiv Hendelsen utløses når panelet vises. Når hendelsen utløses, vil render ()
funksjon kalles, erstatter kontrollelementelementets HTML med en gjengitt mal. Ved å legge ved render ()
invokasjon til aktiv arrangement, i stedet for direkte i konstruktøren, sørger vi for at skjemaet tilbakestilles når panelet navigeres til.
Den siste delen til panelet er skape()
funksjon, hvor vår Trene
posten kommer faktisk til å bli opprettet. Vi bruker formData ()
for å hente brukerens inngang, passerer den til Workout.create ()
.
Nå på å definere app / visninger / trening / form.eco
mal som brukes i render ()
funksjon:
Det er det for vår søknad. Gi det en virvel og lag et par treningsøkter.
Det siste trinnet er å bygge vår applikasjon på disk, og distribuere den. Vi kan gjøre det ved å bruke Hem:
hem bygge
Dette vil serialisere alle JavaScript / CoffeeScript til en fil (offentlige / application.js
), og alle dine CSS / Stylus (offentlig / application.css
). Du må gjøre dette før du trykker nettstedet ditt til en ekstern server, slik at den kan serveres statisk.
Vi skal bruke Heroku til å betjene vår søknad, et flott alternativ for å betjene Node.js og Rails-applikasjoner, og de har en generøs gratis plan. Du må registrere deg for en konto hos dem hvis du ikke har en allerede, samt installere Heroku-perlen.
Nå, alt vi trenger for å distribuere vår app, kjøres noen få Heroku-kommandoer for å få vårt program distribuert.
heroku lage my-ryggraden-app - stakk cedar git add. git commit -m "første commit" git push heroku master heroku åpen
Voila! Du har nå fått en slick mobil applikasjon skrevet i CoffeeScript, HTML5 og CSS3. Vi har mange muligheter nå, for eksempel å pakke inn PhoneGap for å få tilgang til telefonens APIer, tilpasse temaet for Android-telefoner eller legge til støtte uten nett.
Det kan føles som mye å lære, men vi har faktisk dekket mesteparten av Spine API i denne opplæringen. Hvorfor ikke sjekke ut den omfattende dokumentasjonen, og lære litt mer om rammen?
Jeg er sikker på at du har mange spørsmål, så vær så snill å spørre deg i kommentarene og takk så mye for å lese! Ellers må du se vår søsterside, Mobiletuts +, for de beste mobilfokuserte opplæringene på nettet!