Вы находитесь на странице: 1из 19

TableofContents

Introduction

Introduction
 

1.1

1.1

Basics

Basics
 

1.2

1.2
Thesimplestusecase 1.2.1

Thesimplestusecase

1.2.1

1.2.1
Vue-router   1.2.2

Vue-router

 

1.2.2

1.2.2

Advanced

Advanced
 

1.3

1.3
Vuex   1.3.1

Vuex

 

1.3.1

1.3.1

Introduction

WelcometoLearningVue.js

Vue.jsisaJavascriptlibrarytohelpbuildingcomplexuserinterfacesforthebrowser.It

implementsthepatternMVVM(ModelView-ViewModel).Out-of-the-boxitprovidesrich

featuressuchastwo-waydatabindinganddirectives.Youcancreatecomponents,

encapsulatingbehavior,structure(HTML)andstyling(CSS),allowingcodereuse.

Itislightweight,playsnicelywithjQueryandcanbeusedwithmodulebundlerssuchas

WebpackorBrowserify.

TherearetwousecasesforVue.js:

1. Enhanceanexistentpagesbyaddingreactivecomponents

2. Createasinglepageapplication(requiresadd-ons)

Inbothcasesitisagoodchoiceforitssimplicityofuseandflatlearningcurve.

Thisbookmeanstobeacollectionofshorthow-tolike

tutorials.

Thecontentisreleasedinnoparticularorder.

Author

Basics

Basics

1. Thesimplestusecase

2. Vue-router

Thesimplestusecase

Thesimplestusecase

Vue.jsisverygoodtoworkwithdata.Itprovidesmeanstoaccess,modifyandvalidateit.

FurthermoreitactsasthegluebetweenHTMLelementsandthedata,removingfromthe

developertheannoyingtaskofgettingreferencestoDOMelementsjusttoshow/hidethem

orreadtheirvalues.

Thisbarebonesexamplewilljustenable/disablethesubmitbuttonwhenallformfieldsare

filled.ItisasimpleHTMLpagewithVue.jsincludedinascripttag.

Thesetup:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8">
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script src="http://cdnjs.cloudflare.com/ajax/libs/vue/1.0.25/vue.min.js"></script>
<script>
new Vue({
el: 'body'
})
</script>
</body>
</html>

Nothingspecialisgoingonatthemoment:closetothe

andtheinstantiationofaVueobject.AstheonlyparameterpassedtotheVue()methodis

anobjectliteralcontainingsomeconfigurationinformation.Intheexampleabovethe

.Everythingcontainedwithinbodywill

property

beavailabletoVue.js.

</body>
</body>

tagisajavascriptinclude

el
el

attachestheVueobjecttothe

<body>
<body>

Nextweneedaform:

Thesimplestusecase

<body> <form action="#"> <div> <label for="name">Name</label> <input type="text" id="name" name="name"> </div> <div> <label for="email">E-mail</label> <input type="email" id="email" name="email"> </div> <div><button type="submit">Submit</button></div> </form> </body>

Whatistheourgoalhere?Tokeepthesubmitbuttondisableduntilbothfieldsare

filled.Thinkforamoment:"-HowwouldyouaccomplishthisifworkingwithVanillaJSor

jQuery?"Probablyyou'dgetareferencetobothfieldsandreadtheirvalues,right?Well,with

Vue.jsitisalittlebitdifferent.

FirstwearegoingbacktotheVueobjectinstantiationtocreateanobjectwiththedatawe

areinterestedin

new Vue({

el: 'body',

data: {

name: '',

email: ''

}

})

andthenattachthatdatatoourform:

<input type="text" id="name" name="name" v-model="name"> <input type="email" id="email" name="email" v-model="email">

Payattentiontothenewattribute

directreferencetothepropertiescontainedinourdataobjectlivinginsidetheVueobject.

v-model
v-model

includedinbothinputfields.Theycontaina

Thesimplestusecase

ThispropertyisadirectiveanditspurposeistotiethedatatotheHTMLelement.Bydoing

this,everythingtypedinthefieldwillchangethedataintheVueobject.Theoppositeisalso

trueandiftheinformationischangedintheJavascript,let'ssay,bythereturnofanAJAX

call,thenewvaluewillautomaticallybedisplayedintheformfield.

Thishandybehaviouriscalledtwo-waydatabinding.

Wearegettingthere!

Nowitistimetoworkonthebutton,afterall,heisourmaincharacterhere.Toenablethe

desiredbehaviourwearegoingtouseanotherdirective:

conditionallyaddpropertiestoHTMLelementsbasedonthestateofourdata.Inthis

particularcasewe'llmakeuseoftheproperty

v-bind
v-bind

.Thisdirective

disabled

:

<div><button type="submit" v-bind:disabled="(name != '' && email !=
<div><button type="submit" v-bind:disabled="(name != '' && email != '')">Submit</button
></div>

BytheconfigurationaboveVueisinstructedtodothefollowing:addthedisabledattributeto

the

binding,thisisperformedliveandautomatically.ThisisthepowerofVue!.

<button>

whenbothnameandemailarenotempty.Thankstothetwo-waydata

Butthisiskindofdirty,don'tyouthinkso?Whatifwewanttovalidatee-mailstructurebefore

consideringtheformasvalidforsubmission?Well,there'sabetterwaytoimplementthis

validation:computedproperty.

new Vue({

el: 'body',

data: {

name: '',

email: ''

}, computed: { isValid: function () { return this.name != '' && this.email != ''

})

}

}

<div><button type="submit" v-bind:disabled="!isValid">Submit</button></div>

Thesimplestusecase

OnceagainthankstothereactivitynatureofVue.jseverytimeoneoftheproperties

mentionedinthemethod

false.Becausethisisaregularmethodyoucanperformanyothervalidationinsideit.

isValid
isValid

changesthemethodgetsexecuted,returningtrueor

Belowyoufindthecompletesourcecode.Ifyouwannaseeitinactionthere'safiddle

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <form action="#"> <div> <label for="name">Name</label> <input type="text" id="name" name="name" v-model="name"> </div> <div> <label for="email">E-mail</label> <input type="email" id="email" name="email" v-model="email"> </div> <div><button type="submit" v-bind:disabled="!isValid">Submit</button></div> </form> <script src="http://cdnjs.cloudflare.com/ajax/libs/vue/1.0.25/vue.min.js"></script>

 

<script>

new Vue({

el: 'body',

data: {

name: '',

email: ''

}, computed: { isValid: function () { return this.name != '' && this.email != ''

}

}

})

 

</script>

</body>

</html>

!= '' && this .email != '' } } })   </script> </body> </html>
!= '' && this .email != '' } } })   </script> </body> </html>

Vue-router

Vue-router

ThisarticlewasfirstpostedonVue.jsBrasil(http://www.vuejs-brasil.com)

ThemostnotablecharacteristicofaSinglePageApplicationistheperformance.All

interfaceelementsareinplaceandwhenyourserverinfrastructureiswellsetup(theweb

servicethatprovidesthedata)thefeelingusergetswhileusingtheapplicationisthe

applicationislocallyinstalled,becauseoftheshortresponsetime.

AnessentialcomponentinaSPAistheRouterwhichisresponsibleforshowing/hiddingone

ormoreinterfaceelementsdependingontheURL.Thisisitssingleresponsibilitybutit

doesn'tmeanitisasimpletool!

TosupportthearticleanewprojectisgoingtobecreatedwithVue-cli,acommandlinetool

Startingtheproject

Assumingyoualreadyhaveallnecessarytoolsinstalled(node.js,npmandvue-cli)just

tooneofyoursystem'sfolderandexecute

vue init webpack-simple project-name

.

cd
cd
vue init webpack-simple project-name . cd Afteranswetingtothe4questionsabouttheprojets,just execute

Afteranswetingtothe4questionsabouttheprojets,just

execute

timetoinstalltheVue-router(itisNOTlistedasoneoftheproject'sdefaultdependencies):

cd
cd

totheproject'sfolderand

npm install

.Afterthegeneralinstallationofallproject'sdefaultdependencies,itis

npm install --save-dev vue-router

.

Allfilesarenowstoredon/node_modulesdirectoryandwillbeavailableforyourown

scriptforimport

Vue-router

Openuptheprojectinyourfavoritecodeeditorandlocatethefile

basicstructureofaVueobject:

/src/main.js

toseethe

import Vue from 'vue' import App from './App.vue'

new Vue({ el: 'body', components: { App }

})

PayattentiontoAppcomponentbecauseitisgonnabetheparentofallothercomponents

thatmightbecreatedduringdevelopment.

Vue-routerconfiguration

Beforewebeginweneedatleast2componentssowecanmimicsomenavigation.So,

withinthe

contentsjustaddsomethingthatvisuallydifferentiatethem:

/src
/src

folderjustcreateComponentA.vueandComponentB.vue.Astheir

<template> <h1>Componente A</h1> </template>

<template> <h1>Componente B</h1> </template>

Nowgoingbackto

/src/main.js

westarttoconfiguretheVue-router:

import Vue from 'vue' import VueRouter from 'vue-router' // << here import App from './App.vue'

Vue.use(VueRouter) // << and here

new Vue({ el: 'body', components: { App }

})

AtthispointwejustimportVue-routerstraightfromnode_modulesfolderandmakeVue

awareofit.

Vue-router

Nowweimportbothcomponents

import Vue from 'vue' import VueRouter from 'vue-router' import App from './App.vue' import ComponentA from './ComponentA.vue' import ComponentB from './ComponentB.vue'

Vue.use(VueRouter)

new Vue({ el: 'body', components: { App }

})

andthenwemapthembothtotheirroutes:

Vue.use(VueRouter)

const router = new VueRouter()

router.map({ '/component-a': { component: ComponentA

}, '/component-b': { component: ComponentB

},

})

new Vue({

Intheobjectpassedastheonlyparamtothemethodmap()weassignthedesiredURLsto

thecomponentstobedisplayed.NowweneedtoadaptourApp.vuecomponentsoitwill

displaytherightcomponentandthecorrespondentURLisaccessed:

RemoveeverythingcontainedinApp.vuereplacingwiththeHTMLbelow:

<template>

<div>

<router-view></router-view>

</div>

</template>

Vue-router

Thespecialtag

themappedcomponents.You'refreetoaddothertagsclosetoandevenencapsulateit

withinaregularHTMLtag.

<router-view

introducedbytheVue-routerpackageistheplaceholderfor

ThelaststepistoreplacetheVueobjectcreationforthe

sometimescausesconfusionbecauseitisnotclearwheretheVueobjectisbeingcreated.

router.start()

method.Thispart

router.map({ '/componente-a': { component: ComponentA

}, '/componente-b': { component: ComponentB

},

})

router.start(App, '#container')

Pleasenotethatthe

thetag

Sowhereisthiselement?Nowhere!Wearegoingtoadditto/index.html:

start() <router-view
start()
<router-view

methodlinkstheapplication'smaincomponent(theonewith

>)totheDOMelementthatneedstobeobservedbytheVueobject.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>route</title> </head> <body> <div id="container"> <router-view></router-view> </div> <script src="dist/build.js"></script> </body> </html>

andthisisthecatch

touseasinglefilecomponent(*.vue)asintheinstantiatoroftheVue-router.Intheofficial

documentationyou'llseeyouhavetocreateagenericVuecomponent,butthisisnotatall

necessaryandyoucankeepusingthestructureyou'reusedto.

Notethedivwiththeidof"container".Italsocontaina

<router-view>

Belowyoufindthecompletemain.js:

Vue-router

import Vue from 'vue' import VueRouter from 'vue-router' import App from './App.vue' import ComponenteA from './ComponenteA.vue' import ComponenteB from './ComponenteB.vue'

Vue.use(VueRouter)

const router = new VueRouter()

router.map({ '/component-a': { component: ComponentA

}, '/component-b': { component: ComponentB

},

})

router.start(App, '#container')

Tofinishthistutorialreturntoconsoleandexecute

pointitto

npm run dev

or

andinyourfavoritebrowser

http://localhost:8080/#!/component-a

http://localhost:8080/#!/component-b

.

Becauseinarealworldapplicationthequantityofroutertendtobebig,itisadvisedtoadd

thisrouterconfigurationonitownfolder/files,makinguseofthemodulebundlertoaddthem

togetherinawaythatmakessensetotheVueobjecttoconsumeit.

Here'sthelinktotheofficialdocumentationfortheVue-router:

Advanced

Advanced

1. Vuex

Vuex

Vuex

Understandingtheproblemitsolves

Whenyou'rebuildingabrowserbasedapplicationitisnotunusualtolosecontroloverthe

flowofthedataitmanages.

Inthosekindsofapplicationdataisnotonlywhattheusersendstotheserverbutalsowhat

controlsthedisplayofinterfacecontrols.Soforinstanceyouchangeavalueinacomponent

andanotheronethatissupposedtobevisible,foranyreasonitisnowhidden.Thisiswhat

wecallsideeffects.

Asyourapplicationgrowsitbecomesanightmaretodealwithallthesideeffectsthatarise. Theusualwaytosharedataacrossyoutreeofcomponentsisbyusingevents,upand downthetree.ItisOKwhenyouimmediatelycaptureadispatchedeventbutwhenthe eventiscapturedhigherorlowerinthetree,you'llquicklygetyourselfwondering"where thateventcomesfrom ".

EntertheSingleSourceofTruth

Singlesourceoftruthistostructureyourdatainawaythatitisnotduplicatedanywhere

withinyourapplication.Thinkaboutitasadorsalspineofyourapplication.Allyour

componentswillgetdatafromitandsavebacktoit,makingiteasytoknowwherethe

changecamefrom.

Thereareseveraladvantagesoftakingthisapproach:

1. Youhaveacentralizedplacetoadd/changeitsdata;

2. Itisavailableforallyourcomponents;

3. Nocomponentchangesitsdatadirectlythusassuringdataconsistency;

4. Relatedtoolsmakedebuggingasmootherexperience.

Vuex

ItistheVueimplementationofFluxwhichinturnistheFacebook'simplementationfor

SingleSourceofTruth.TheintegrationwithVue'sreactivitysystemistransparentand

requiressomesimpleconfigurationstepsbeforeitisreadytouse.

Vuex

Thefirststepistoinstallitusingaregularnpmcommand

Afterwardsgotothefileinwhichyou'vecreatedtheVueinstance,instructVuetouseVuex

andattachastoretoit:

npm install vuex --save-dev

.

import Vue from 'vue' import Vuex from 'vuex'

Vue.use(Vuex)

new Vue({ el: 'body', store: new Vuex.Store({})

})

InsidetheVuex.Store()methodyou'llhavetopassanobjecttwopropertiesasfollows:

1. TheStatewhichisaregularJavascriptobjectcontainingthedatayouwanttoshare

acrossyourapplication;

2. Themethodsthatchangethestate.They'recalledMutationMethods.

Asanexampletakethesnippetofcodeabove:

new Vue({ el: 'body', store: new Vuex.Store({ state: { user: { name: '', email: ''

}

}, mutations: { SET_USER (store, obj) { store.user = obj.user

})

})

}

}

Asyoumighthaveimaginedthequantityofbothstatepropertiesandmutationmethodswill

growlargerthanthis,sowerelyonmodulebundlerstosetupVuexsomewhereelseinour

filesystemandjustimportithere:

createthefile:/src/vuex/store.js

Vuex

import Vue from 'vue' import Vuex from 'Vuex'

Vue.use(Vuex)

export default new Vuex.Store({ state: { user: { name: '', email: ''

}

}, mutations: { SET_USER (store, obj) { store.user = obj.user

}

})

}

andinyour/src/main.js:

import Vue from 'vue' import store from './vuex/store'

Vue.use(Vuex)

new Vue({

el: 'body',

store

})

ReadingandSettingdatainastore

NowthatwehaveourstorefullyconfiguredandattachedtotheVueobject,itistimetostart

usingit!

Thebeautyisthatitisimmediatelyavailabletoallyourcomponents.Thesamewayyou're

usedtopropertiessuchasmethods:{},data:{}andcomputed:{}younowhavethevuex:

{}property.Let'sgetstarted:

Vuex

<script> export default { props: ['some-property-here'],

vuex: {

getters: {},

actions: {}

},

data () { // << some local state return { whatever: ''

}

}

}

</script>

IfwewanttoaccesstheuserpropertyofourVuexStore,itisjustamatterofsettingupa

getter

vuex: { getters: { user: store => store.user

},

actions: {}

},

andthenuseitasanormalinternalproperty:

this.user

.

Nowyouneedtochangeuserdata.Beforemovingforwardanotetokeepinmind:you

CANNOTchangeVuexStatedirectly.IfyouaskmeifitispossibleI'dsay"yesitis"but

highlydiscouraged.Thisisbecauseifyouwanttofindourhowapropertyisset,yougofora

singleplaceinsteadofopeningupallyoucomponentfilestodiscoverwherethechange

camefrom.

Sohowtochangeit?

Byusingactions.Theyaremethodsliketheonesyoucreateinsidethemethods:{}

propertyofyourcomponentsbutyoudeclaretheminaspecialplace:withinvuex:{

actions:{}}property.Bydoingthisyouassurethefirstparameterreceivedbyyourmethod

willbeaninstanceoftheVuexStore.

WeareinterestedinaspecialmethodcontainedinthatStoreobject,amethodcalled

dispatch().Wewilluseittoinvokeamutation,thisoneresponsibleforsettingupdateinour

VuexStore.

Vuex

vuex: { getters: { user: store => store.user

}, actions: { setUser ({dispatch}, obj) { dispatch('SET_USER', obj)

},

}

}

methods: { ordinaryButtonClickHandler () { let user = { user: { username: 'New username', email: 'email@email.com'

}

}

this.setUser(user) // << the action gets called after a button click

}

}

Payattentiontothisspecificpartbecausethisthemostconfusingpart:

dispatch('SET_USER',

obj)
obj)

.Firstwereceivethismethoddispatch()byusingDestructuringAssignment,anewand

veryusefulfeatureofES2015.Thinkaboutitasaneventdispatcherwithasinglepurpose:

invokeamutation.Youdon'tmanuallycaptureitanywhereasyouwoulddowitharegular

dispatchedevent.ThankstoVueitgoesstraighttoyourmutationsobjectinyourVuex

configurationandthepropermethodisinvoked.

Thenameofthemutationmethodisthefirstparameterandtheobjectthemutationwill

receiveisthesecondone.Whenitgetstothemutation,yourstoreisfinallychangedandall

yourcomponentsobservingtheVuexStorewillautomaticallybeupdated.

SupportingTools

ThereisapowerfultooltosupportdevelopmentwithVue.jscalledVueDevtools,aGoogle

Chromeextensionthatletsyouinspectyourtreeofcomponents,interactwiththeminthe

ConsoleandinteractwithyourVuexStore,takingadvantageofTimeTravelforthedata.

Itshowsalltheinvokedmutationsandyoucannavigatethroughit,seeingchangesinreal

time.

Vuex

Vuex Conclusion Theofficialdocumentationstatesthat Vuexisnotsuitableforallkindsofproject butI

Conclusion

TheofficialdocumentationstatesthatVuexisnotsuitableforallkindsofprojectbutI

founditsosimpletousethatIincludeitinallofmyprojects.Itfeelsnatural.

NowthatitisclearthatVuexisacentralizedstoreforyourdatawhichmakesiteasierto

handlethestateofyourapplication,keepinmindyoucanalsohavealocalstateinall

yourcomponents.ThedecisiontoaddittoVuexStoreortokeepitlocalisforyouto

make.Doyouneedthispieceofdataanywhereelseinmyapplication?IftheanswerisYES

thanyoushouldaddittoVuexStore.