More Related Content Similar to 옛날 웹 개발자가 잠깐 맛본 Vue.js 소개 (20) More from beom kyun choi (20) 옛날 웹 개발자가 잠깐 맛본 Vue.js 소개1. 옛날 웹 개발자가 잠깐 @ 본
Vue.js 소개
최범균, 2,d90r8s@2,d90r8s.n.t, @OKKY 20180419
자료: /tt4s: :::.s10d.s/,r..n.t 2,d90r8s
2. 나 = 옛J 웹 (서S) 개R자
• 요즘 h론트 모름
• b신 언어
• ).6 ~
• TEpe.cript
• g키a, 모L, T더 M
• npm, Earn, De2pack, parcel, 2a2el, ReqCireJ., A,(, ..
• C..
• .aAA, +eAA, …
• b신 h레임워c
• React, AngClar 2 , VCe.jA
• eV트
• ,=ca6, JaAmine, …
2
3. C = M날 웹 (서버) 개발P
• 아는 A
• S론트
• 3q=ery
• 약간의 Ang=lar 1 B험
• C++ 초J Bootstrap
• 서버
• +pring ),C
• (+P, t1ymeleaf
3
6. 요건
• 빨리(2주 안P)
• 일단 빨리 A들어 시범 운영 시작
• 동적인 요소
• 조건P 따라 보이고 안 보이6 구성 요소
• 폼 등록후 목록P 결2 반영
• SPA(S)n(le Pa(e A,,)
• 개발자 S심 고객 요구6 아님
• 나름 요즘 기술
• 개발자 S심 고객 요구6 아님
6
8. 결정에 영향을 준 h 가지 자d
• 개j자 조o
• httEH://Htat:of?H.8oB/201(/front-:nd/r:HuAtH/
• 3u:.?H가 ,nguAar 재낌
• 앞으c k우겠다는 개j자 n율도 높음
• 다e 프b임워크와의 n교
• httEH://kr.Ku:?H.org/K2/guid:/8oBEariHon.htBA
• ,nguAar 2에p 3u:.?Hc 넘yN 이유 (2:a8tf q택하지 v은 이유)
• httE://7it.Ay/2/B133a (원i) httE://7it.Ay/2.ygZAf (l역)
• 학t Rq 공u ip V현 r도 단s함
• 과연 3u:.?H가 앵귤aZ g엑트m다 좋을X?
• httE://7it.Ay/2uXq:fu (원i) httE://7it.Ay/2K0-X0: (l역)
)
9. 몇 가지 Vue..s jb
• 템플릿 이용 선V적 렌더링
• 모델 뷰 양방향 바인딩(2 2(y )-nd-ng) 지원
• d포넌i
• 라우g(SPA)
• 이벤i버S
• 단일 파일 d포넌i
• 글A벌 Pe 관리
• 점a적으A 기9 채택 가9
• P대적으A 빠른 n습
• 한글 문서
9
10. 간단 샘[
'0
;ttpD://=D:<dd>e.net/madv<CuD/y');vC;=/
,d<v <d="app".
,;(.T델,/;(.
이름: ,<nput type="text" v-model="name" /.
암호: ,<nput type="paDDwACd"
v-model="password" /.
,;(.바인딩,/;(.
이름: ,<nput type="text" v-bind:value="name" /.
암호: ,<nput type="paDDwACd"
:value="password" /.
,;(.값,/;(.
,u>.
,><.이름 : {{ name }},/><.
,><.암호 : {{ password }},/><.
,/u>.
,<nput type="buttAn"
v-on:click="init()" va>ue="초기]" /.
,/d<v.
,DcC<pt type="text/=avaDcC<pt"
DCc=";ttpD://.../vue.=D".,/DcC<pt.
,DcC<pt type="text/=avaDcC<pt".//,!301/T/3
vaC app = new Vue!{
el: #app ,
data: {
name: "",
password: ""
},
methods: {
init: :unct<An!" {
t;<D.name = "<n<t";
t;<D.paDDwACd = "";
}
}
}"
//44.
,/DcC<pt.
11. +, 기본 구성: 모델 + 뷰 + 뷰모델
뷰 템플릿
뷰모델뷰
데이터, 모델
12. 앱의 2본 1성 요소: data, comp,ted
• data
• 모델, :인딩 대상
• 양방향 :인딩
• 모델의 변경을 뷰에 반영
• --model로 뷰 폼의 변경을 모델에 반영
• comp,ted
• 계산 속성
• 연관된 data 속성이 변경하면 comp,ted 속성 변경
2
13. ]제
+,
v:r :pp 3 n>w 6u>#{
>l0 " :pp"&
data0 {
name0 ""& birthyear0 LhisY>:r ' +.& parentCheck0 f:ls>
}&
computed0 {
years0 fun<Lion#) {
v:r r>L 3 []1
for#v:r v 3 LhisY>:r ' ,0 1 v <3 LhisY>:r 1 v++)
r>L(push#v)1
r>Lurn r>L1
}&
isUnderage0 fun<Lion#) {
r>Lurn LhisY>:r ' this.birthyear < +-1
}
}&
m>Lho=s0 {
r>g0 fun<Lion#) {
if #this.isUnderage !! !this.parentCheck)
…
}
}
})
hLLps0))jsfi==l>(n>L)m:=virus)ujor5=yx)
hLLps0))jsfi==l>(n>L)m:=virus)w+:,/mLm) 0 <ompuL>= g>L)s>L ]
<=iv i=3":pp"4
<form4
<=iv4
<l:;>l for3"n:m>"4이Y<)l:;>l4
<inpuL Lyp>3"L>xL" i=3"n:m>" v-model="name" )4
<)=iv4
<=iv4
<l:;>l for3";irLhy>:r"4[년<)l:;>l4
<s>l><L i=3";irLhy>:r" v-model="birthyear"4
<opLion v'for3"y>:r in years" 0v:lu>3"y>:r"4
{{ y>:r }}년
<)opLion4
<)s>l><L4
<)=iv4
<=iv v-if="isUnderage"4
<inpuL Lyp>3"<h><k;ox"
i=3"p<hk" v-model="parentCheck" )4
<l:;>l for3"p<hk"4미성년 V의<)l:;>l4
<)=iv4
<)form4
<inpuL Lyp>3";uLLon" v'on0<li<k3"r>g#)" v:lu>3"등록" )4
<)=iv4
14. 뷰 템플릿
• 콧bi(1ust(ch, 표현d : {{ d }}
• 뷰 모델o a성n 해당 l{에 삽s
• 디렉티브 : 태그에 u용
• v-t,;t : 특b 문t 처리(예, < à <&
• v-ht1l : 특b 문t 미처리
• v-)ind : 태그 a성에 모델 단방향 바인딩
• v-1od,l : 모델과 f방향 바인딩
• v-sho: : 보hwy h부(dis4l(< c}r a성 사용
• v-i-, v-,ls,, v-,ls,-i- : v건에 따라 보hx(v건에 e 맞m면 렌더링 e함
• v--or : 반복
• v-on : p벤트
• …
14
15. 뷰 템플릿 예
"5
<d/v>
<1abe1 -or="name">이름<!1abe1>
</n5ut t<5e="text" /d="name" v-model="name" !>
<!d/v>
<d/v>
<1abe1 -or="b/rth<ear">생=<!1abe1>
<se1ect /d="b/rth<ear" v-model="birthyear">
<o5t/on v-for="year in years" v-bind:value="year">
{{ year }}=
<!o5t/on>
<!se1ect>
<!d/v>
<d/v v-if="isUnderage">
<! v-if="new Date().getFullYear() - birthyear < 14" >
</n5ut t<5e="checkbox" /d="5arentCheck" v-model="parentCheck" !>
<1abe1 -or="5arentCheck">{{ birthyear }}=생은 C성= >의 필요<!1abe1>
<!d/v>
</n5ut t<5e="button" v-on:click="reg()" va1ue="등록" !>
16. 자바 스aN트 식 S용 가능
• 콧수Y, 디렉d브 식에서 자바 스aN트 S용 가능
• 남발하지 O 것
'(
EE =u<b6r " ' }}
EE >: - 'Y.1' ) '/O' }} à eb가 나을 수 있음
EE <6ssag6.s?lit '').r6v6rs6 ).j>i= '') }} à eb가 나을 수 있음
<div v-bi=d)id+"'list-' " id",</div,
17. 앱c 기본 구Y a소: met;A7s
• 앱c 기능 e공
• f수염 hi식, 디렉gV에서 사b 가능
(7
vaC app . new Vue"{
e>: ! app!,
7ata: {
name: "", 5<Ct;yeaC: t;<sYeaC - (),
paCent1;ec=: fa>se, s;AwA:e: tCue
},
methods: {
reg: funct<An"# {…},
agem: funct<An"# {
CetuCn t;<sYeaC - t;<s.5<Ct;yeaC,
},
showToggle: funct<An"# {
t;<s.s;AwA:e . !t;<s.s;AwA:e
}
}
}#
-7<v v-<f."s;AwA:e" v-on:click="showToggle"/
{{ agem() }}
-'7<v/
-7<v v-<f."!s;AwA:e" v-on:click="showToggle"/
나dh시
-'7<v/
18. 이벤트 처리
• 다양한 구성 요소에서 이벤트 처리 가능
• v-on 디렉티브
• 예: v-on:cl.ck, v-on:key8p, v-on:68b1.t, v-on:c-an,e …
• 수식어
• 이벤트
• 6top, p5event, capt85e, once, …
• key8p 이벤트용
• 키코드: 키코드
• 별칭: ente5, tab, e6c, delete, 6pace, 8p, do:n, left, 5.,-t, ct5l, alt, 6-.ft, 1eta
• 조합: ct5l65
18
19. 이벤트 예
'9
.=Bv B=/":pp">
.: hI>f/"#" v-on:click.prevent="help">도움Y./:>
.foIE>
.=Bv>
.D:;>D foI/"F:E>">이름./D:;>D>
.BFput typ>/"t>xt" B=/"F:E>" v-Eo=>D/"F:E>"
v-on:keyup.enter="goTo('birthyear')" />
./=Bv>
.=Bv>
.D:;>D foI/";BIthy>:I">생T./D:;>D>
.BFput typ>/"t>xt" B=/";BIthy>:I"
v-Eo=>D/";BIthy>:I"
v-on:keyup.enter="goNext"
=:t:-F>xt/"I>g"/>
./=Bv>
./foIE>
.BFput B=/"I>g" typ>/";uttoF"
v-on:click="reg" v:Du>/"V록" />
./=Bv>
v:I thBs9>:I / F>N D:t>(".g>t4uDD9>:I("-
v:I :pp / F>N 8u>({
>D, #:pp #
=:t:, { … }#
E>tho=s, {
h>Dp, fuF<tBoF(" { … }#
goTo, fuF<tBoF(id" {
=o<uE>Ft.g>tED>E>Ft1yI=(B=".fo<us("-
}#
go6>xt, fuF<tBoF(event" {
v:I F>xtI= / >v>Ft.t:Ig>t.=:t:s>t.F>xt-
v:I >D> / =o<uE>Ft.g>tED>E>Ft1yI=(F>xtI="-
Bf (>D>" >D>.fo<us("-
}#
I>g, fuF<tBoF(" {
:D>It("V록""-
}
}
}"
https,//jsfB==D>.F>t/E:=vBIus/;f<)(ph8/
21. 컴포+트
• UI 구성 요소
• 템플릿 + 앱
• 조립
• 부모 자식 관계
• 부모 à 자식: 속성
• 자식 à 부모: 이2트
• 일부 공통 UI 구성 요소 재사용
• :: 1튼, 그-I, 모,창
21
22. 컴포넌트 예
22
(>empl/>e i2)"user-info-template">
(2iv cl/==)"c/<2">
(2iv cl/==)"c/<2-b:2y">
(2iv>
(=p/n cl/==)"b/2ge b/2ge-p<im/<y">주H(/=p/n>
(=p/n>{{ info./22<e== }}(/=p/n>
(/2iv>
(2iv>
(=p/n cl/==)"b/2ge b/2ge-p<im/<y">H,(/=p/n>
(=p/n>{{ info.hp }}(/=p/n>
(/2iv>
(2iv>
(=p/n cl/==)"b/2ge b/2ge-p<im/<y">계약(/=p/n>
(=p/n>{{ info.c:n></c> }}(/=p/n>
(/2iv>
(2iv>
(=p/n cl/==)"b/2ge b/2ge-p<im/<y">미납(/=p/n>
(=p/n>{{ info.unp/y }}(/=p/n>
(/2iv>
(/2iv>
(/2iv>
(/>empl/>e>
Vue.component 'user-info'" {
template' '#user-info-template'"
props' -'info'.
})
23. 컴포넌트 사N
'(
<d;v ;d,"3pp" c<3ss,"co>t3;>er"-
<user-info v-bind:info="infoData"></user-info>
<3ct;v;ty-<;st v-b;>d)3ct;v;t;es,"3ct;v;t;es"-</3ct;v;ty-<;st-
<3ct;v;ty-for= v-o>)3dded,"3dd/ew"-</3ct;v;ty-for=-
</d;v-
v3r 3pp , >ew VDe({
e<) "#3pp"#
d3t3) {
infoData) {}#
activities) [2
}#
cre3ted) fD>ct;o>(" {
t:;s.<o3d(";
}#
=et:ods) {
<o3d) fD>ct;o>(" {
3x;os.get(/so=ed3t3/"
.t:e>((respo>se" ,- {
t:;s.;>fo.3t3 , respo>se.d3t3.;>fo;
t:;s.3ct;v;t;es , respo>se.d3t3.3ct;v;t;es;
}".c3tc:((error" ,- {
co>so<e.<og(error";
}";
}#
…
}
}";
VDe.co=po>e>t( user-info # {
te=p<3te) #Dser-;>fo-te=p<3te #
props) [ info 2
}"
24. 컴V넌트 이벤트 발생
()
4ue.7ompoAeAt( a7t=v=ty-:oDm # {
template, #a7t=v=ty-:oDm-template #
data, :uA7t=oA(" {
DetuDA {
type, ""# Desult, ""# N
}-
}#
met<ods, {
De;, :uA7t=oA(" {
vaD Aew17t / {
"date", :oDmat2ate(Aew 2ate(""#
"Desult", t<=s.Desult#
"type", t<=s.type}-
this.$emit("added", newAct)-
}
}
}"
.d=v =d/"app" 7lass/"7oAta=AeD">
.d=v v-s<ow/"loaded">
.useD-=A:o v-6=Ad,=A:o/"=A:o">./useD-=A:o>
.a7t=v=ty-l=st ,a7t=v=t=es/"a7t=v=t=es">./a7t=v=ty-l=st>
.a7t=v=ty-:oDm v-on:added="addNew">./a7t=v=ty-:oDm>
./d=v>
./d=v>
vaD app / Aew 4ue({
el, "#app"#
...
met<ods, {
addNew, :uA7t=oA(Aew17t" {
t<=s.a7t=v=t=es.pus<(Aew17t"-
}#
...
}
}"-
<ttps,//>s:=ddle.Aet/madv=Dus/(D;'zs76/
25. 컴포넌트 분리
• 동적 요소가 많5수록 영25 구분해서 컴포넌트로 분리
25
무지 긴 자바스크립트
무지 긴 템플릿
격한 휠 소리
27. vu7-rout7r 간단 예제
')
-d:v :d."3pp" c<3ss."co>t3:>7r"/
-d:v/
<router-link to="/contracts">목록</router-link>
<router-link to="/help">도움말</router-link>
-/d:v/
<router-view></router-view>
-/d:v/
-t7=p<3t7 :d."co>tr3cts-t7=p<3t7"/
-d:v/
-h(/목록-/h(/
…
-/d:v/
-/t7=p<3t7/
-t7=p<3t7 :d."h7<p-t7=p<3t7"/
-d:v/
-h(/도움말-/h(/
-/d:v/
-/t7=p<3t7/
v3r contractsComp . {
t7=p<3t7: #co>tr3cts-t7=p<3t7#
d3t3: 8u>ct:o>(" {
r7tur> {
co>tr3cts: [2
},
}#
cr73t7d: 8u>ct:o>(" {
…
}
},
v3r helpComp . {
t7=p<3t7: #h7<p-t7=p<3t7
},
v3r rout7r . new VueRouter({
routes: [
{
path: "/contracts",
name: "contracts",
component: contractsComp
},
{
path: "/help",
name: "help",
component: helpComp
}
]
}),
v3r v= . >7w Vu7({
7<: "#3pp"#
router: router
}",
https://;s8:dd<7.>7t/=3dv:rus/hp8(r;db/
28. 동V 라우팅 사용
(8
;ttCs://=s:<88le.net/ma8v<rus/xno=a'uC/
-temClate <8."contracts-temClate"/
-8<v/
-;)/R록-/;)/
-table class."table"/
…
-tbo8y/
-tr v-:or."cont <n contracts"/
-t8/
-router-l<n>
:to."'/contracts/' + cont.num"/
{{ cont.num }}
-/router-l<n>/
-/t8/
-t8/{{ cont.a88ress }}-/t8/
-t8/{{ cont.name }}-/t8/
-/tr/
-/tbo8y/
-/table/
-/8<v/
-/temClate/
var router . new 2ueRouter({
routes: 3
…
{
path: "/contracts/:num",
name: "8eta<l"#
comConent: 8eta<l0omC
}#
…
]
}",
var vm . new 2ue({
el: "#aCC"#
router: router
}",
var 8eta<l0omC . {
temClate: #8eta<l-temClate#
8ata: :unct<on(" {
return {
<n:o: {}
},
}#
create8: :unct<on(" {
var num . this.$route.params.num,
t;<s.loa8(num",
}#
met;o8s: {
loa8: :unct<on(num" {
...
}
}
},
29. 경로 변수 변경 감지
21
v:r <=t:il7omp 5 {
t=mpl:t=2 '#<=t:il-t=mpl:t='$
<:t:2 >un;tion"# {
r=turn {
in>o2 {}
}3
}$
;r=:t=<2 >un;tion"# {
v:r num 5 this. rout=.p:r:ms.num3
this.lo:<"num#3
}$
beforeRouteUpdate2 >un;tion"to$ >rom$ n=xt# {
this.lo:<"to.params.num#3
n=xt"#3
}$
4t=mpl:t= i<5"<=t:il-t=mpl:t="6
4<iv6
4h36상세2
4strong6{{ in>o.num }}4'strong6
4'h36
4<iv6
{{ in>o.:<<r=ss }}
4'<iv6
4<iv6
4rout=r-linC to5"/contracts/13579"6
8이[ )3-/19
4'rout=r-linC6
4rout=r-linC to5"/contracts/24680"6
8다음 2,.0(9
4'rout=r-linC6
4'<iv6
4'<iv6
4't=mpl:t=6
https2''js>i<<l=.n=t'm:<virus'xnoj:(up'
30. l]s [d
• 글로벌 l]s 발생# cf
• 부모/ne 관계가 g닌 m의 구a h소L rf
• o당u 사it면 pj# 격t게 사it면 코V가 꼬m
('
https://;s7:ddle.net/=3dv:ADs/v/D/'7)v/
v3A eventBus , new 0De(";
0De.co=ponent(3ct:v:ty-7oA=# {
te=pl3te: #3ct:v:ty-7oA=-te=pl3te#
d3t3: 7Dnct:on(" {
AetDAn { type: ""# AesDlt: ""# …};
}#
=ethods: {
Aeg: 7Dnct:on(" {
v3A new-ct , {
"d3te": 7oA=3t.3te(new .3te(""#
"AesDlt": th:s.AesDlt# "type": th:s.type
};
eventBus.$emit(
'activityAdded',
newAct);
}
}
}";
0De.co=ponent(3ct:v:ty-l:st# {
te=pl3te: #3ct:v:ty-l:st-te=pl3te#
d3t3: 7Dnct:on(" {
AetDAn { 3ct:v:t:es: [] };
}#
cAe3ted: 7Dnct:on(" {
eventBus.$on(
'activityAdded',
this.activityAdded);
th:s.lo3d(";
}#
=ethods: {
3ct:v:ty-dded: 7Dnct:on(new-ct" { … }#
lo3d: 7Dnct:on(" { ... }
}
}";
31. fc2 값 e맷d a리
+)
Vue.filter( Ls>rno , fLn<tion(v:lL>" { '' 글로벌 fc
r>tLrn v:lL>.sL;string((, -" # "-" # v:lL>.sL;string(-"3
}"
v:r :pp 5 n>w 9L>({
>l2 #:pp ,
=:t:2 {
no2 ")2+,-./01(",
n:m>2 "이상은",
<o=>2 "7"
},
filt>rs2 { '' 로b fc
gr:=>2 fLn<tion(v:lL>" {
if (v:lL> 55 7 " r>tLrn 정h원 3
r>tLrn 준h원 3
}
}
}"3
4=iv i=5":pp"6
4A+6h원4'A+6
번g2 {{ no | userno }} 4;r'6
이V2 {{ n:m> }}4;r'6
등급2 {{ <o=> | grade }}
4'=iv6
Attps2''jsfi==l>.n>t'm:=virLs'o8:w:n:+'
32. 사c한 lh 사r
• ]e 데io 변X
• mn 데io j근'pd
32
SAO ANN 1 Lew =ue"V
eJ. ! ANN!,
CAtA. V
NeOsoL. V
LAme. !i[!
},
Bities. [
VLAme. !서g!, BoCe. !;E:!},
VLAme. !부a!, BoCe. !4<;3N!},
VLAme. !제l!, BoCe. !JEJ<!}
]
},
methoCs. V
uNCAte). EuLBtioL"# V '' 반f >
this.cities[0] = VLAme. !서g(!, BoCe. !;E:<L(!}/
},
uNCAte2. EuLBtioL"# V '' 반f :
this.cities[0].code = !;E:<L!!/
},
uNCAte3. EuLBtioL"# V '' 반f :
Vue.set"this.Bities, (, VLAme. !서g!, BoCe. !;E:<L!}#/
}
}
}#
0h32VV NeOsoL.LAme }} 0'h32
VV NeOsoL.address.code1 }}
0!--
5ALLot OeAC NOoNeOtU !BoCe)! oE uLCeEiLeC
--2
0uJ2
0Ji S-EoO1"B iL Bities"2VVB.LAme}}-VVB.BoCe}} 0'Ji2
0'uJ2
httNs.''jsEiCCJe.Let'mACSiOus'g-LNLN3,'
33. Lz 특s
• wat/h : c성 변H vn
• 트랜ra : dP메ja 효J
• https://jsfiddl1:1t//hrisAfritz/sLrhk".//
• 단k 파k w포넌트 : 템플릿 + J+ + C++
• w포넌트 단h 관리
• Au1C : og "상태 + L능 + 변H"
• w포넌트 간 데j터/j벤트 주고 받는 xT p거로 복mS 감b
• lu HTTP 클라je트 fi
• ACios vt: https://3ithu./om/aCios/aCios
33
34. 좋았던 점
• 4대적으로 낮은 학습 시간
• 단순한 구성 요소
• 기존 자바스크립트 지식만으로 충분
• 간단하게 시작할 수 있음
• 최신 3드 도구가 없어도 됨
• 컴포넌트 단위 관리
34