Shin-JaeHeon / vuejs-interview-questions-korean

VueJS interview questions in Korean language

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

vuejs-interview-questions-korean

List of 300 VueJS Interview Questions

Contributor

  • ๐Ÿ“‹ ๋ณธ ๋ฌธ์„œ๋Š” sudheerj์˜ vuejs-interview-questions์˜ ๋ฒˆ์—ญ๋ณธ์ž…๋‹ˆ๋‹ค.
  • โญ ์ด ํ”„๋กœ์ ํŠธ๊ฐ€ ๋งˆ์Œ์— ๋“œ์…จ๋‹ค๋ฉด STAR๋ฅผ ๋ˆŒ๋Ÿฌ์ฃผ์„ธ์š”.
  • โœ”๏ธ ํ’€ ๋ฆฌํ€˜์ŠคํŠธ๋Š” ์–ธ์ œ๋“  ํ™˜์˜์ž…๋‹ˆ๋‹ค.

Table of Contents


No. Questions
1 VueJS๋ž€ ๋ฌด์—‡์ธ๊ฐ€
2 VueJS์˜ ์ฃผ์š” ํŠน์ง•์€
3 VueJS์˜ ๋ผ์ดํ”„์‚ฌ์ดํด(lifecycle) ํ•จ์ˆ˜๋Š”
4 ์กฐ๊ฑด๋ถ€ ์ง€์‹œ์ž(conditional directives)๋ž€
5 v-show์™€ v-if์˜ ์ฐจ์ด์ ์€
6 v-for๋ฅผ ์“ฐ๋Š” ๋ชฉ์ ์€
7 Vue ์ธ์Šคํ„ด์Šค๋ž€
8 ์—ฌ๋Ÿฌ ์—˜๋ฆฌ๋จผํŠธ๋“ค์„ ํ•œ ๋ฒˆ์— ์กฐ๊ฑด๋ถ€๋กœ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐฉ๋ฒ•์€
9 key ์†์„ฑ์„ ์ด์šฉํ•ด ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€
10 ๊ฐ™์€ ์—˜๋ฆฌ๋จผํŠธ์—์„œ v-for์™€ v-if๋ฅผ ํ•จ๊ป˜ ์“ฐ๋ฉด ์•ˆ ๋˜๋Š” ์ด์œ ๋Š”
11 v-for์—์„œ key ์†์„ฑ์ด ํ•„์š”ํ•œ ์ด์œ 
12 ๋ฐฐ์—ด์„ ๋ณ€ํ™”์‹œํ‚ค๋Š” ํ•จ์ˆ˜(Mutation method)๋ž€
13 ๋ฐฐ์—ด์„ ๋Œ€์ฒดํ•˜๋Š” ํ•จ์ˆ˜(Non-mutation method)๋ž€
14 ๋ฐฐ์—ด ๋ณ€๊ฒฝ์„ ํƒ์ง€ํ•  ๋•Œ ์ฃผ์˜ํ•  ์ 
15 ๊ฐ์ฒด ๋ณ€๊ฒฝ์„ ํƒ์ง€ํ•  ๋•Œ ์ฃผ์˜ํ•  ์ 
16 v-for๋ฅผ ํŠน์ • ํšŸ์ˆ˜๋งŒํผ ๋ฐ˜๋ณตํ•˜๋Š” ๋ฐฉ๋ฒ•์€
17 v-for๋กœ ํ…œํ”Œ๋ฆฟ์„ ๋ฐ˜๋ณตํ•˜๋Š” ๋ฐฉ๋ฒ•์€
18 ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€
19 Vue์—์„œ ์ด๋ฒคํŠธ ์ˆ˜์‹์–ด(Event modifier)๋ž€
20 ํ‚ค ์ˆ˜์‹์–ด(Key modifiers)๋ž€
21 ํ‚ค ์ˆ˜์‹์–ด๋ฅผ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•˜๋Š” ๋ฐฉ๋ฒ•์€
22 ์‹œ์Šคํ…œ ์ˆ˜์‹์–ด ํ‚ค(System modifier key)๋ž€
23 ๋งˆ์šฐ์Šค ๋ฒ„ํŠผ ์ˆ˜์‹์–ด(Mouse button modifier)๋ž€?
24 v-model์˜ ์—ญํ• ์€
25 v-model์—์„œ ์ง€์›๋˜๋Š” ์ˆ˜์‹์–ด๋Š”?
26 ์ปดํฌ๋„ŒํŠธ(Component)๋ž€
27 props๋ž€?
28 ์ปดํฌ๋„ŒํŠธ์—์„œ ์—ฌ๋Ÿฌ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์“ฐ๋ ค๋ฉด?
29 ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ด๋ฒคํŠธ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€?
30 ์‚ฌ์šฉ์ž ์ •์˜์˜ input ์ปดํฌ๋„ŒํŠธ์—์„œ v-model์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฒ•์€?
31 slots์ด๋ž€?
32 ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ „์—ญ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ๋ฒ•์€?
33 ์ปดํฌ๋„ŒํŠธ์˜ ์ง€์—ญ ๋“ฑ๋ก์ด ํ•„์š”ํ•œ ์ด์œ ๋Š”?
34 ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์—์„œ ์ „์—ญ ๋“ฑ๋ก๊ณผ ์ง€์—ญ ๋“ฑ๋ก์˜์ฐจ์ด์ ์€?
35 prop ํƒ€์ž…์˜ ์ข…๋ฅ˜๋Š”?
36 props์— ์˜ํ•œ ๋ฐ์ดํ„ฐ ํ๋ฆ„์€?
37 Props๊ฐ€ ์•„๋‹Œ ์†์„ฑ์€?
38 Props๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ๋ฐฉ๋ฒ•์€?
39 ์ปดํฌ๋„ŒํŠธ์—์„œ v-model์„ ์‚ฌ์šฉ์ž ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์€?
40 ํŠธ๋žœ์ง€์…˜ ํšจ๊ณผ๋ฅผ ๋„ฃ์„ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€?
41 Vue Router๋ž€?
42 Vue Router๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€?
43 ๋™์  ๋ผ์šฐํŠธ ๋งค์นญ์ด๋ž€?
44 ๋ผ์šฐํ„ฐ params๋ฅผ ๋ฐ˜์‘์ ์œผ๋กœ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์€?
45 ๋ผ์šฐํŠธ์˜ ์šฐ์„  ์ˆœ์œ„๋Š”?
46 ์ค‘์ฒฉ๋œ ๋ผ์šฐํŠธ๋ž€?
47 ์‹ฑ๊ธ€ ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ๋ž€?
48 ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ(separation of concerns)์ด๋ž€?
49 ์‹ฑ๊ธ€ ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ๋Š” ์™œ ํ•„์š”ํ• ๊นŒ?
50 filter๋ž€?
51 filter๋ฅผ ์ „์—ญ์  ๋˜๋Š” ์ง€์—ญ์ ์œผ๋กœ ๋งŒ๋“œ๋Š” ๋ฒ•์€?
52 filter๋ฅผ ์—ฐ์†ํ•ด ์“ฐ๋Š” ๋ฐฉ๋ฒ•์€?
53 filter์— ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์„๊นŒ?
54 ํ”Œ๋Ÿฌ๊ทธ์ธ์ด๋ž€?
55 ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์€?
56 ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€?
57 ๋ฏน์Šค์ธ์ด๋ž€?
58 ์ „์—ญ ๋ฏน์Šค์ธ์ด๋ž€?
59 CLI ํ™˜๊ฒฝ์—์„œ ๋ฏน์Šค์ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฒ•์€
60 ๋ฏน์Šค์ธ์˜ ์˜ต์…˜์ด ์ปดํฌ๋„ŒํŠธ์˜ ์˜ต์…˜๊ณผ ์ถฉ๋Œํ•œ๋‹ค๋ฉด?
61 ๋ฏน์Šค์ธ์˜ ๋ณ‘ํ•ฉ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉ์ž ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์€?
62 ์‚ฌ์šฉ์ž ์ •์˜ ์ง€์‹œ์ž(Custom directive)๋ž€?
63 ์ง€์‹œ์ž๋ฅผ ์ง€์—ญ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ๋ฒ•์€?
64 ์ง€์‹œ์ž์— ์˜ํ•ด ์ œ๊ณต๋˜๋Š” ๋ผ์ดํ”„ ์‚ฌ์ดํด ํ›…์€?
65 ๋””๋ ‰ํ‹ฐ๋ธŒ ํ›…์˜ ์ „๋‹ฌ์ธ์ž๋Š”?
66 ์ง€์‹œ์ž์— ์—ฌ๋Ÿฌ ๊ฐ’๋“ค์„ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€?
67 ์ง€์‹œ์ž ํ›…์—์„œ ํ•จ์ˆ˜ ์•ฝ์–ด๋Š”?
68 render ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š”?
69 render ํ•จ์ˆ˜๋ž€?
70 createElement ํ•จ์ˆ˜๋ž€
71 ๊ฐ€์ƒ ๋…ธ๋“œ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€?
72 render ํ•จ์ˆ˜์™€ ํ…œํ”Œ๋ฆฟ์„ ๋น„๊ตํ•œ๋‹ค๋ฉด?
73 ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ(Functional component)๋ž€?
74 Vue์™€ React์˜ ๊ณตํ†ต์ ์€?
75 Vue์™€ React์˜ ์ฐจ์ด์ ์€?
76 Vue๊ฐ€ React์— ๋น„ํ•ด ๋‚˜์€ ์ ์€
77 React๊ฐ€ Vue์— ๋น„ํ•ด ๋‚˜์€ ์ ์€
78 Vue์™€ AngularJS์˜ ์ฐจ์ด์ ์€
79 ๋™์  ์ปดํฌ๋„ŒํŠธ๋ž€?
80 keep-alive ํƒœ๊ทธ๋ž€?
81 ๋น„๋™๊ธฐ ์ปดํฌ๋„ŒํŠธ(Async component)๋ž€?
82 ๋น„๋™๊ธฐ ์ปดํฌ๋„ŒํŠธ ํŒฉํ† ๋ฆฌ ํŒจํ„ด์ด๋ž€?
83 ์ธ๋ผ์ธ ํ…œํ”Œ๋ฆฟ(inline templates)์ด๋ž€?
84 X-Templates์ด๋ž€?
85 ์žฌ๊ท€ ์ปดํฌ๋„ŒํŠธ(recursive components)๋ž€?
86 ์ปดํฌ๋„ŒํŠธ ์‚ฌ์ด์˜ ์ˆœํ™˜ ์ฐธ์กฐ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€?
87 CSP ํ™˜๊ฒฝ์—์„œ Vue ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋นŒ๋“œํ•˜๋Š” ๋ฒ•์€
88 ์ „์ฒด ๋นŒ๋“œ์™€ ๋Ÿฐํƒ€์ž„ ๋นŒ๋“œ์˜ ์ฐจ์ด์ ์€?
89 Vue์˜ ๋นŒ๋“œ ์ข…๋ฅ˜๋Š”?
90 ์›นํŒฉ์—์„œ Vue ์„ค์ •์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์€?
91 Vue ์ปดํŒŒ์ผ๋Ÿฌ์˜ ๋ชฉ์ ์€?
92 DevTool์ด๋ž€
93 VueJS์˜ ๋ธŒ๋ผ์šฐ์ € ์ง€์›์€?
94 CDN์œผ๋กœ Vue๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€?
95 ๊ฐ•์ œ๋กœ ์—…๋ฐ์ดํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์€?
96 ํ…œํ”Œ๋ฆฟ์—์„œ once ์ง€์‹œ์ž๋ฅผ ์“ฐ๋Š” ์ด์œ ๋Š”?
97 ๋ฃจํŠธ Vue ์ธ์Šคํ„ด์Šค์— ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ•์€?
98 Vue๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๊ธฐ์—…๋“ค์€?
99 renderError ๋ฉ”์†Œ๋“œ์˜ ๋ชฉ์ ์€?
100 ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ง์ ‘ ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ•์€?
101 vuex๋ž€?
102 ์ƒํƒœ ๊ด€๋ฆฌ ํŒจํ„ด์˜ ์ฃผ์š” ๊ตฌ์„ฑ ์š”์†Œ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?
103 Vuex์—์„œ ๋‹จ๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ํ๋ฆ„ ๋ชจ๋ธ์„ ์–ด๋–ป๊ฒŒ ํ‘œํ˜„ํ•ฉ๋‹ˆ๊นŒ?
104 vuejs loader๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?
105 ์›นํŒฉ์—์„œ vue loader๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์€?
106 vue-loader์˜ Asset URL ํ•ธ๋“ค๋ง ๊ทœ์น™์€?
107 vue-loader์—์„œ ์ „์ฒ˜๋ฆฌ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด?
108 ๋ฒ”์œ„ CSS(Scoped CSS)๋ž€?
109 ๋ฒ”์œ„ CSS์™€ ์ „์—ญ CSS๋ฅผ ํ•จ๊ป˜ ์“ธ ์ˆ˜ ์žˆ์„๊นŒ?
110 ๋ฒ”์œ„ CSS๊ฐ€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ฒŒ ํ•˜๋Š” ๋ฐฉ๋ฒ•์€?
  1. VueJS๋ž€ ๋ฌด์—‡์ธ๊ฐ€

    Vue.js๋Š” ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์ง„๋ณด์ ์ธ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. ํ•ต์‹ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋ทฐ ๋ ˆ์ด์–ด๋งŒ ์ดˆ์ ์„ ๋งž์ถ”์–ด, ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‚˜ ๊ธฐ์กด ํ”„๋กœ์ ํŠธ์™€์˜ ํ†ตํ•ฉ์ด ์‰ฝ์Šต๋‹ˆ๋‹ค.

  2. VueJS์˜ ์ฃผ์š” ํŠน์ง•์€

    ์•„๋ž˜์˜ ํ•ญ๋ชฉ๋“ค์€ VueJS์˜ ์ฃผ์š” ํŠน์ง•๋“ค์ž…๋‹ˆ๋‹ค.

    1. ๊ฐ€์ƒ DOM(Virtual DOM): VueJS์—์„œ๋Š” ReactJS, Ember ํ”„๋ ˆ์ž„์›Œํฌ์™€ ์œ ์‚ฌํ•˜๊ฒŒ ๊ฐ€์ƒ DOM์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€์ƒ DOM์€ ์›๋ณธ HTML DOM์„ ํ‘œํ˜„ํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ์ƒ์˜ ๊ฐ€๋ฒผ์šด DOM ํŠธ๋ฆฌ๋กœ, ์›๋ณธ DOM์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๊ณ  ์—…๋ฐ์ดํŠธ๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    2. ์ปดํฌ๋„ŒํŠธ(Components): VueJS ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์—˜๋ฆฌ๋จผํŠธ๋“ค์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    3. ํ…œํ”Œ๋ฆฟ(Templates): VueJS๋Š” Vue ์ธ์Šคํ„ด์Šค ๋ฐ์ดํ„ฐ์™€ DOM์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” HTML ๊ธฐ๋ฐ˜์˜ ํ…œํ”Œ๋ฆฟ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
    4. ๋ผ์šฐํŒ…(Routing): ํŽ˜์ด์ง€์˜ ์ „ํ™˜์€ vue-router๋ฅผ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค.
    5. ์ €์šฉ๋Ÿ‰(Light weight): VueJS๋Š” ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ์™€ ๋น„๊ตํ•ด ์ €์šฉ๋Ÿ‰์ž…๋‹ˆ๋‹ค.
  3. VueJS์˜ ๋ผ์ดํ”„์‚ฌ์ดํด(lifecycle) ํ•จ์ˆ˜๋Š”

    ๋ผ์ดํ”„์‚ฌ์ดํด ํ›…(Lifecycle hook)์€ ์‚ฌ์šฉ์ค‘์ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์–ด๋–ค ์ˆœ์„œ๋กœ ๋™์ž‘ํ•˜๋Š”์ง€๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ํ›…์„ ์ด์šฉํ•ด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ธ์ œ ์ƒ์„ฑ๋˜๊ณ , ์–ธ์ œ DOM์— ์ถ”๊ฐ€๋˜๋ฉฐ, ์–ธ์ œ ์—…๋ฐ์ดํŠธ๋˜๊ณ  ์–ธ์ œ ์‚ฌ๋ผ์ง€๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ๋‹ค์ด์–ด๊ทธ๋žจ์„ ํ†ตํ•ด VueJS์˜ ์ „๋ฐ˜์ ์ธ ๋ผ์ดํ”„์‚ฌ์ดํด์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    1. Creation(์ดˆ๊ธฐํ™”): Create ํ›…์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ DOM์— ์ถ”๊ฐ€๋˜๊ธฐ ์ „์— ์‹คํ–‰๋˜๋Š” ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„๊ฐ€ ๋ Œ๋”๋ง ๋‹จ๊ณ„ ์ „์— ์ปดํฌ๋„ŒํŠธ์— ์„ค์ •ํ•ด์•ผ ํ•  ๊ฒƒ๋“ค์ด ์žˆ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ›…๊ณผ๋Š” ๋‹ค๋ฅด๊ฒŒ, Create ํ›…์€ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง์—์„œ๋„ ์ง€์›๋˜๋Š” ํ›…์ž…๋‹ˆ๋‹ค.

      1. beforeCreate: beforeCreate ํ›…์€ ์ปดํฌ๋„ŒํŠธ ์ดˆ๊ธฐํ™” ๋‹จ๊ณ„ ์ค‘ ๊ฐ€์žฅ ์ฒ˜์Œ์œผ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์ด ํ›…์—์„œ๋Š” ์ปดํฌ๋„ŒํŠธ์˜ data๋ฅผ ๊ด€์ฐฐํ•˜๊ณ , ์ด๋ฒคํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋‹จ๊ณ„์—์„œ data๋Š” ์•„์ง๊นŒ์ง€ ๋ฐ˜์‘์ ์ด์ง€ ์•Š์œผ๋ฉฐ, ์ปดํฌ๋„ŒํŠธ์˜ ๋ผ์ดํ”„์‚ฌ์ดํด์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ด๋ฒคํŠธ ์—ญ์‹œ ์„ค์ •๋˜์ง€ ์•Š์€ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.
          new Vue({
            data: {
             count: 10
            },
            beforeCreate: function () {
              console.log('Nothing gets called at this moment')
              // `this` points to the view model instance
              console.log('count is ' + this.count);
            }
          })
             // count is undefined
      1. created: created ํ›…์€ Vue ์ธ์Šคํ„ด์Šค๊ฐ€ ์ด๋ฒคํŠธ๋ฅผ ์„ค์ •ํ•˜๊ณ  data๋ฅผ ๊ด€์ฐฐํ•  ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด ๋‹จ๊ณ„์—์„œ ํ…œํ”Œ๋ฆฟ์€ ์•„์ง ๋งˆ์šดํŠธ๋˜๊ฑฐ๋‚˜ ๋ Œ๋”๋ง๋˜์ง€ ์•Š์•˜์ง€๋งŒ, ์ด๋ฒคํŠธ๋“ค์ด ํ™œ์„ฑํ™”๋˜๋ฉฐ data์— ๋ฐ˜์‘์ ์œผ๋กœ ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
        new Vue({
          data: {
           count: 10
          },
          created: function () {
            // `this` points to the view model instance
            console.log('count is: ' + this.count)
          }
        })
           // count is: 10

      ์ฃผ์˜: Create ํ›…์—์„œ๋Š” DOM์— ์ง์ ‘ ์ ‘๊ทผํ•˜๊ฑฐ๋‚˜ ๋งˆ์šดํŠธํ•  ์—˜๋ฆฌ๋จผํŠธ(this.$el)์— ์ง์ ‘ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์ ์„ ๊ธฐ์–ตํ•˜์„ธ์š”.

    2. Mounting(DOM ์ถ”๊ฐ€): Mount ํ›…์€ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ๋‹จ๊ณ„๋กœ, ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜๊ธฐ ์ง์ „์ด๋‚˜ ์งํ›„์— ์ปดํฌ๋„ŒํŠธ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค.

      1. beforeMount: beforeMount ํ›…์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ DOM์— ์ถ”๊ฐ€๋˜๊ธฐ ์ง์ „์— ์‹คํ–‰๋˜๋Š” ํ›…์ž…๋‹ˆ๋‹ค.
        new Vue({
          beforeMount: function () {
            // `this` points to the view model instance
            console.log(`this.$el is yet to be created`);
          }
        })
      1. mounted: mounted ํ›…์€ ๋ฐ˜์‘์ ์ธ data, ํ…œํ”Œ๋ฆฟ, ๋ Œ๋”๋ง๋œ DOM(this.$el) ๋ชจ๋‘์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด์„œ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ํ›…์ž…๋‹ˆ๋‹ค. ํ”ํžˆ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์™ธ๋ถ€์—์„œ ๊ฐ€์ ธ์˜ค๋Š”(fetch) ์šฉ๋„๋กœ ๋งŽ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
      <div id="app">
          <p>Iโ€™m text inside the component.</p>
      </div>
        new Vue({
          el: '#app',
          mounted: function() {
            console.log(this.$el.textContent); // I'm text inside the component.
          }
        })
    3. Updating (์žฌ ๋ Œ๋”๋ง): Update ํ›…์€ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์˜ ๋ฐ˜์‘์ ์ธ ์†์„ฑ์ด ๋ณ€ํ–ˆ๊ฑฐ๋‚˜, ๊ทธ ์™ธ์˜ ๊ฒƒ๋“ค์ด ์žฌ ๋ Œ๋”๋ง์„ ์ผ์œผํ‚ฌ ๋•Œ ์‹คํ–‰๋˜๋Š” ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค.

      1. beforeUpdate: beforeUpdate ํ›…์€ ์ปดํฌ๋„ŒํŠธ์˜ data๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด ์—…๋ฐ์ดํŠธ ์‚ฌ์ดํด์ด ์‹œ์ž‘๋  ๋•Œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
      <div id="app">
        <p>{{counter}}</p>
      </div>
      ...// rest of the code
        new Vue({
          el: '#app',
          data() {
            return {
              counter: 0
            }
          },
           created: function() {
            setInterval(() => {
              this.counter++
            }, 1000)
          },
      
          beforeUpdate: function() {
            console.log(this.counter) // Logs the counter value every second, before the DOM updates.
          }
        })
      1. updated: updated ํ›…์€ ์ปดํฌ๋„ŒํŠธ์˜ data๊ฐ€ ๋ณ€ํ•˜์—ฌ ์žฌ ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚œ ํ›„์— ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
      <div id="app">
        <p ref="dom">{{counter}}</p>
      </div>
      ...//
        new Vue({
          el: '#app',
          data() {
            return {
              counter: 0
            }
          },
           created: function() {
            setInterval(() => {
              this.counter++
            }, 1000)
          },
          updated: function() {
            console.log(+this.$refs['dom'].textContent === this.counter) // Logs true every second
          }
        })
    4. Destruction(ํ•ด์ฒด): Destruction ํ›…์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋” ์ด์ƒ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค.

      1. beforeDestroy: beforeDestroy ํ›…์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ•ด์ฒด๋˜๊ธฐ ์ง์ „์— ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์ด ํ›…์€ ๋ฐ˜์‘์ ์ธ ์ด๋ฒคํŠธ๋“ค์ด๋‚˜ data๋“ค์„ ํ•ด์ฒดํ•˜๋Š” ํ›…์œผ๋กœ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. ์ด ๋‹จ๊ณ„์—์„œ ์ปดํฌ๋„ŒํŠธ๋Š” ์—ฌ์ „ํžˆ ๋ฌธ์ œ์—†์ด ์ž˜ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.
      new Vue ({
        data() {
          return {
            message: 'Welcome VueJS developers'
          }
        },
      
        beforeDestroy: function() {
          this.message = null
          delete this.message
        }
      })
      1. destroyed: destroyed ํ›…์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ•ด์ฒด๋˜๊ณ  ๋‚œ ์งํ›„์— ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์ง€์‹œ์ž๋“ค์˜ ๋ฐ”์ธ๋”ฉ์ด ํ•ด์ œ๋˜์—ˆ์œผ๋ฉฐ, ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์ œ๊ฑฐ๋œ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.
      new Vue ({
          destroyed: function() {
            console.log(this) // Nothing to show here
          }
        })
  4. ์กฐ๊ฑด๋ถ€ ์ง€์‹œ์ž(conditional directives)๋ž€

    VueJS๋Š” ์กฐ๊ฑด์— ๋”ฐ๋ผ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ณด์—ฌ์ฃผ๊ฑฐ๋‚˜ ์ˆจ๊ธธ ์ˆ˜ ์žˆ๋Š” ์ง€์‹œ์ž๋“ค์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ง€์‹œ์ž๋“ค์€ v-if, v-else, v-else-if and v-show๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

    1. v-if: v-if ์ง€์‹œ์ž๋Š” ์กฐ๊ฑด์— ๋”ฐ๋ผ DOM ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์•„๋ž˜์˜ ๋ฒ„ํŠผ์€ isLoggedIn์˜ ๊ฐ’์ด false๋ผ๋ฉด ๋‚˜ํƒ€๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

    <button v-if="isLoggedIn">Logout</button>

    ์—˜๋ฆฌ๋จผํŠธ๋“ค์„ <template> ํƒœ๊ทธ๋กœ ๊ฐ์‹ผ๋‹ค๋ฉด, ํ•˜๋‚˜์˜ v-if๋งŒ์œผ๋กœ ์—ฌ๋Ÿฌ ์—˜๋ฆฌ๋จผํŠธ๋“ค์˜ ์กฐ๊ฑด์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์•„๋ž˜์™€ ๊ฐ™์ด label๊ณผ button ํƒœ๊ทธ๋ฅผ ํ•˜๋‚˜์˜ ์กฐ๊ฑด ์ง€์‹œ์ž๋กœ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <template v-if="isLoggedIn">
      <label> Logout </button>
      <button> Logout </button>
    </template>

    2. v-else: ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์—์„œ if์˜ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š๋Š” ๊ฒฝ์šฐ else๋กœ ๋„˜์–ด๊ฐ€๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, v-else ์ง€์‹œ์ž๋Š” ์ธ์ ‘ํ•œ v-if ์ง€์‹œ์ž ๋˜๋Š” v-else-if ์ง€์‹œ์ž๊ฐ€ false์ผ ๋•Œ๋งŒ ๊ทธ ๋‚ด์šฉ์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ์ด ์ง€์‹œ์ž์—๋Š” ์กฐ๊ฑด์„ ์ง€์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์•„๋ž˜์˜ ์˜ˆ์‹œ๋Š” isLoggedIn์ด false์ผ ๋•Œ(์ฆ‰ ๋กœ๊ทธ์ธ ๋œ ์ƒํƒœ๊ฐ€ ์•„๋‹ ๋•Œ), v-else๋ฅผ ์ด์šฉํ•ด ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

    <button v-if="isLoggedIn"> Logout </button>
    <button v-else> Log In </button>

    3. v-else-if: v-else-if ์ง€์‹œ์ž๋Š” v-if ์ด์™ธ์˜ ๋‹ค๋ฅธ ์กฐ๊ฑด์„ ์ถ”๊ฐ€๋กœ ํ™•์ธํ•ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, v-else-if ์ง€์‹œ์ž๋ฅผ ์ด์šฉํ•ด ifLoginDisabled์˜ ๊ฐ’์ด true์ผ ๋•Œ๋Š” ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ๋Œ€์‹  ํ…์ŠคํŠธ๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <button v-if="isLoggedIn"> Logout </button>
    <label v-else-if="isLoginDisabled"> User login disabled </label>
    <button v-else> Log In </button>

    4. v-show: v-show ์ง€์‹œ์ž๋Š” v-if ์ง€์‹œ์ž์™€ ๋น„์Šทํ•œ ๊ธฐ๋Šฅ์„ ํ•˜์ง€๋งŒ, DOM์— ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์ถ”๊ฐ€๋œ ์ƒํƒœ์—์„œ CSS์˜ display ๊ฐ’์„ ์ด์šฉํ•ด ๋ณด์—ฌ์ฃผ๊ณ  ์ˆจ๊น€์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค. v-show ์ง€์‹œ์ž๋Š” ์กฐ๊ฑด๋ฌธ์ด ์ž์ฃผ ํ† ๊ธ€๋  ๋•Œ ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค.

    <span v-show="user.name">Welcome user,{{user.name}}</span>
  5. v-show์™€ v-if์˜ ์ฐจ์ด์ ์€

    v-show์™€ v-if์˜ ์ฃผ์š” ์ฐจ์ด์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    1. v-if๋Š” ์กฐ๊ฑด์ด ์ผ์น˜ํ•˜๋Š” ์—˜๋ฆฌ๋จผํŠธ๋งŒ DOM์— ๋ Œ๋”๋งํ•˜๋Š” ๋ฐ˜๋ฉด, v-show๋Š” ๋ชจ๋“  ์—˜๋ฆฌ๋จผํŠธ๋ฅผ DOM์— ๋ Œ๋”๋งํ•œ ํ›„ CSS๋ฅผ ์ด์šฉํ•ด ๋‚ด์šฉ์„ ๋ณด์—ฌ์ฃผ๊ฑฐ๋‚˜ ์ˆจ๊น๋‹ˆ๋‹ค.
    2. v-if์™€ v-else-if์—์„œ๋Š” v-else๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, v-show์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
    3. v-if๋Š” ํ† ๊ธ€ํ•  ๋•Œ ๋†’์€ ๋ Œ๋”๋ง ๋น„์šฉ์ด ๋“ค์ง€๋งŒ, v-show๋Š” ์ดˆ๊ธฐ์˜ ๋ Œ๋”๋ง ์ž‘์—…์—์„œ ๋†’์€ ๋น„์šฉ์ด ๋“ญ๋‹ˆ๋‹ค. ์ฆ‰, v-show๋Š” ์š”์†Œ๋ฅผ ์ž์ฃผ ์ผœ๊ณ  ๋„๋Š” ๊ฒฝ์šฐ ์„ฑ๋Šฅ ์ƒ์˜ ์ด์ ์ด ์žˆ์ง€๋งŒ, ์ดˆ๊ธฐ ๋ Œ๋”๋ง ์ž‘์—…์—์„œ๋Š” v-if๊ฐ€ ๋” ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.
    4. v-if๋Š” <template>ํƒœ๊ทธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ v-show๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  6. v-for๋ฅผ ์“ฐ๋Š” ๋ชฉ์ ์€

    v-for ์ง€์‹œ์ž๋Š” ๋ฐฐ์—ด์ด๋‚˜ ๊ฐ์ฒด๋ฅผ ์ˆœํ™˜ํ•˜๋ฉด์„œ ๋ฐ˜๋ณต์ ์ธ ๋ Œ๋”๋ง์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

    1. ๋ฐฐ์—ด์˜ ๊ฒฝ์šฐ:
    <ul id="list">
      <li v-for="(item, index) in items">
        {{ index }} - {{ item.message }}
      </li>
    </ul>
    
    var vm = new Vue({
      el: '#list',
      data: {
        items: [
          { message: 'John' },
          { message: 'Locke' }
        ]
      }
    })

    ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ˆœํ™˜๋ฌธ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ, in ์™ธ์—๋„ of๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    1. ๊ฐ์ฒด์˜ ๊ฒฝ์šฐ:
    <div id="object">
      <div v-for="(value, key, index) in user">
        {{ index }}. {{ key }}: {{ value }}
      </div>
    </div>
    
    var vm = new Vue({
      el: '#object',
      data: {
        user: {
          firstName: 'John',
          lastName: 'Locke',
          age: 30
        }
      }
    })
  7. Vue ์ธ์Šคํ„ด์Šค๋ž€

    ๋ชจ๋“  Vue ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ Vue ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด Vue ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ฉด์„œ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ vm(ViewModel์˜ ์ถ•์•ฝํ˜•)์ด๋ผ๋Š” ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•ด Vue ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ Vue ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    var vm = new Vue({
      // options
    })

    ์œ„์˜ ์ฝ”๋“œ์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ, ์˜ต์…˜์„ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ์˜ต์…˜์€ API ๋ฌธ์„œ์—์„œ ์ž์„ธํžˆ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  8. ์—ฌ๋Ÿฌ ์—˜๋ฆฌ๋จผํŠธ๋“ค์„ ํ•œ ๋ฒˆ์— ์กฐ๊ฑด๋ถ€๋กœ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐฉ๋ฒ•์€

    ๋ Œ๋”๋ง์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๋Š” <template> ํƒœ๊ทธ์— v-if ์ง€์‹œ์ž๋ฅผ ์ ์šฉํ•จ์œผ๋กœ์จ ์—ฌ๋Ÿฌ ์—˜๋ฆฌ๋จผํŠธ๋“ค์„ ํ•œ ๋ฒˆ์— ์กฐ๊ฑด๋ถ€๋กœ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์•„๋ž˜์™€ ๊ฐ™์ด ์œ ํšจํ•œ ์‚ฌ์šฉ์ž์ธ ๊ฒฝ์šฐ์— ํ•œํ•ด์„œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <template v-if="condition">
      <h1>Name</h1>
      <p>Address</p>
      <p>Contact Details</p>
    </template>
  9. key ์†์„ฑ์„ ์ด์šฉํ•ด ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€

    Vue๋Š” ๊ฐ€๋Šฅํ•œ ํ•œ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๋ Œ๋”๋งํ•˜๋ ค ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ๋งŒ๋“ค๊ธฐ๋ณด๋‹ค๋Š” ์žฌ์‚ฌ์šฉํ•˜๋ ค ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Š” ๋ช‡ ๊ฐ€์ง€ ์ƒํ™ฉ์—์„œ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, input ์—˜๋ฆฌ๋จผํŠธ๋ฅผ v-if์™€ v-else ๋ธ”๋ก ์–‘์ชฝ์—์„œ ์‚ฌ์šฉํ•˜๋ฉด, input ์—˜๋ฆฌ๋จผํŠธ๋Š” ์กฐ๊ฑด๋ฌธ์— ๋”ฐ๋ผ ๋ฐ”๋€Œ์ง€ ์•Š๊ณ  ์ตœ์ดˆ์— ๋ Œ๋”๋ง ๋œ ์—˜๋ฆฌ๋จผํŠธ์˜ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

    <template v-if="loginType === 'Admin'">
      <label>Admin</label>
      <input placeholder="Enter your ID">
    </template>
    <template v-else>
      <label>Guest</label>
      <input placeholder="Enter your name">
    </template>

    ์ด ๊ฒฝ์šฐ์—์„œ input ์—˜๋ฆฌ๋จผํŠธ๋Š” ์žฌ์‚ฌ์šฉ๋˜์–ด์„œ๋Š” ์•ˆ ๋˜๊ธฐ ๋•Œ๋ฌธ์—, key ์†์„ฑ์„ ์ด์šฉํ•ด ๋‘ ๊ฐœ์˜ input ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ณ„๊ฐœ์˜ ๊ฒƒ์œผ๋กœ ์ทจ๊ธ‰ํ•˜๋„๋ก ์„ ์–ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

        <template v-if="loginType === 'Admin'">
          <label>Admin</label>
          <input placeholder="Enter your ID" key="admin-id">
        </template>
        <template v-else>
          <label>Guest</label>
          <input placeholder="Enter your name" key="user-name">
        </template>

    ์œ„์˜ ๊ฒฝ์šฐ๋Š” ๋‘ ๊ฐœ์˜ input ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ๋ณ„๊ฐœ์˜ ๊ฒƒ์œผ๋กœ ์ทจ๊ธ‰๋˜๋ฉฐ ์„œ๋กœ์—๊ฒŒ ์–ด๋–ค ์˜ํ–ฅ๋„ ๋ผ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  10. ๊ฐ™์€ ์—˜๋ฆฌ๋จผํŠธ์—์„œ v-for์™€ v-if๋ฅผ ํ•จ๊ป˜ ์“ฐ๋ฉด ์•ˆ ๋˜๋Š” ์ด์œ ๋Š”

    v-for ์ง€์‹œ์ž๋Š” v-if ๋ณด๋‹ค ๋” ๋†’์€ ์šฐ์„  ์ˆœ์œ„๋ฅผ ๊ฐ–๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ํ•œ ์—˜๋ฆฌ๋จผํŠธ ๋‚ด์—์„œ v-for์™€ v-if๋ฅผ ํ•จ๊ป˜ ์“ฐ๋Š” ๊ฒƒ์€ ๊ถŒ์žฅ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์œ  ๋•Œ๋ฌธ์— ๋‘ ์ง€์‹œ์ž๋ฅผ ํ•จ๊ป˜ ์“ฐ๊ณค ํ•ฉ๋‹ˆ๋‹ค.

    1. ๋ฆฌ์ŠคํŠธ์˜ ์š”์†Œ๋ฅผ ํ•„ํ„ฐ๋งํ•˜๊ธฐ ์œ„ํ•ด ์˜ˆ๋ฅผ ๋“ค์–ด, v-if ์ง€์‹œ์ž๋ฅผ ์ด์šฉํ•ด ๋ฆฌ์ŠคํŠธ์— ์žˆ๋Š” ์•„์ดํ…œ์„ ํ•„ํ„ฐ๋งํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.
    <ul>
      <li
        v-for="user in users"
        v-if="user.isActive"
        :key="user.id"
      >
        {{ user.name }}
      <li>
    </ul>

    ์ด ๊ฒฝ์šฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์ „์— computed ์†์„ฑ์„ ์ด์šฉํ•ด ํ•„ํ„ฐ๋ง๋œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    computed: {
      activeUsers: function () {
        return this.users.filter(function (user) {
          return user.isActive
        })
      }
    }
    ...... //
    ...... //
    <ul>
      <li
        v-for="user in activeUsers"
        :key="user.id">
        {{ user.name }}
      <li>
    </ul>
    1. ๋ฆฌ์ŠคํŠธ ์ž์ฒด๊ฐ€ ์ˆจ๊ฒจ์ ธ์•ผ ํ•  ๋•Œ ์˜ˆ๋ฅผ ๋“ค์–ด, v-if๋ฅผ ์ด์šฉํ•ด ๋ฐ˜๋ณต๋˜๋Š” ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆจ๊ธฐ๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.
    <ul>
      <li
        v-for="user in users"
        v-if="shouldShowUsers"
        :key="user.id"
      >
        {{ user.name }}
      <li>
    </ul>

    ์ด ๊ฒฝ์šฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์กฐ๊ฑด๋ฌธ์„ ์ƒ์œ„ ์—˜๋ฆฌ๋จผํŠธ๋กœ ์˜ฎ๊น€์œผ๋กœ์จ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <ul v-if="shouldShowUsers">
      <li
        v-for="user in users"
        :key="user.id"
      >
        {{ user.name }}
      <li>
    </ul>
  11. v-for์—์„œ key ์†์„ฑ์ด ํ•„์š”ํ•œ ์ด์œ 

    Vue์—์„œ ๊ฐœ๋ณ„ DOM ๋…ธ๋“œ๋“ค์„ ์ถ”์ ํ•˜๊ณ  ๊ธฐ์กด ์—˜๋ฆฌ๋จผํŠธ์˜ ์žฌ์‚ฌ์šฉ/์žฌ์ •๋ ฌ์„ ์œ„ํ•ด, v-for์˜ ์š”์†Œ์— ๊ณ ์œ ํ•œ key ์†์„ฑ์„ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. key์— ๋Œ€ํ•œ ์ด์ƒ์ ์ธ ๊ฐ’์€ ๊ฐ ํ•ญ๋ชฉ์„ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋Š” ๊ณ ์œ ํ•œ ID์ž…๋‹ˆ๋‹ค.

    <div v-for="item in items" :key="item.id">
      {{item.name}}
    </div>

    ๋ฐ˜๋ณต๋˜๋Š” DOM ๋‚ด์šฉ์ด ๋‹จ์ˆœํ•œ ๊ฒฝ์šฐ๋‚˜ ์˜๋„์ ์ธ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์œ„ํ•ด ๊ธฐ๋ณธ ๋™์ž‘์— ์˜์กดํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋ฅผ ์ œ์™ธํ•˜๋ฉด, ๊ฐ€๋Šฅํ•˜๋ฉด ์–ธ์ œ๋‚˜ v-for์— key๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. Note: ๊ฐ์ฒด๋‚˜ ๋ฐฐ์—ด์ฒ˜๋Ÿผ, ๊ธฐ๋ณธ ํƒ€์ž…(Primitive value)์ด ์•„๋‹Œ ๊ฐ’์„ ํ‚ค๋กœ ์‚ฌ์šฉํ•ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค. ๋ฌธ์ž์—ด์ด๋‚˜ ์ˆซ์ž๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

  12. ๋ฐฐ์—ด์„ ๋ณ€ํ™”์‹œํ‚ค๋Š” ํ•จ์ˆ˜(Mutation method)๋ž€

    ์ด๋ฆ„์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ, ๋ฐฐ์—ด์„ ๋ณ€ํ™”์‹œํ‚ค๋Š” ํ•จ์ˆ˜(mutation methods)๋Š” ์›๋ณธ ๋ฐฐ์—ด์„ ๋ณ€๊ฒฝ์‹œํ‚ต๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ํ•จ์ˆ˜๋Š” ๋ทฐ(view) ์—…๋ฐ์ดํŠธ๋ฅผ ์ผ์œผํ‚ต๋‹ˆ๋‹ค.

    1. push()
    2. pop()
    3. shift()
    4. unshift()
    5. splice()
    6. sort()
    7. reverse()

    ์˜ˆ๋ฅผ ๋“ค์–ด, ์•„๋ž˜์™€ ๊ฐ™์ด todos ๋ฐฐ์—ด์— push ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚ค๋ฉด ๋ทฐ ์—…๋ฐ์ดํŠธ๊ฐ€ ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค.

    vm.todos.push({ message: 'Baz' })
  13. ๋ฐฐ์—ด์„ ๋Œ€์ฒดํ•˜๋Š” ํ•จ์ˆ˜(Non-mutation method)๋ž€

    ๋ฐฐ์—ด์„ ๋Œ€์ฒดํ•˜๋Š” ํ•จ์ˆ˜๋Š” ์›๋ณธ ๋ฐฐ์—ด์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ , ํ•ญ์ƒ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ํ•จ์ˆ˜๋Š” ๋ฐฐ์—ด์„ ๋Œ€์ฒดํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

    1. filter()
    2. concat()
    3. slice()

    ์˜ˆ๋ฅผ ๋“ค์–ด, ์•„๋ž˜์™€ ๊ฐ™์ด status ์†์„ฑ์— ๋”ฐ๋ผ todos ๋ฐฐ์—ด์„ ํ•„ํ„ฐ๋งํ•œ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    vm.todos = vm.todos.filter(function (todo) {
      return todo.status.match(/Completed/)
    })

    Vue๊ฐ€ DOM์„ ํšจ์œจ์ ์œผ๋กœ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์ „์ฒด ๋ฆฌ์ŠคํŠธ๊ฐ€ ์ƒˆ๋กœ ๋ Œ๋”๋ง๋˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

  14. ๋ฐฐ์—ด ๋ณ€๊ฒฝ์„ ํƒ์ง€ํ•  ๋•Œ ์ฃผ์˜ํ•  ์ 

    Vue๋Š” ์•„๋ž˜์˜ ๋‘ ๊ฐ€์ง€ ๊ฒฝ์šฐ์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ฐ์ง€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

    1. ์ธ๋ฑ์Šค๋กœ ๋ฐฐ์—ด์— ์žˆ๋Š” ํ•ญ๋ชฉ์„ ์ง์ ‘ ํ• ๋‹นํ•˜๋Š” ๊ฒฝ์šฐ
    vm.todos[indexOfTodo] = newTodo
    1. ๋ฐฐ์—ด์˜ ๊ธธ์ด๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ฒฝ์šฐ
    vm.todos.length = todosLength

    ์ด๋Š” set๊ณผ splice ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ์ฒซ ๋ฒˆ์งธ ๊ฒฝ์šฐ

    // Vue.set
    Vue.set(vm.todos, indexOfTodo, newTodoValue)
    // Array.prototype.splice
    vm.todos.splice(indexOfTodo, 1, newTodoValue)

    ๋‘ ๋ฒˆ์งธ ๊ฒฝ์šฐ

    vm.todos.splice(todosLength)
  15. ๊ฐ์ฒด ๋ณ€๊ฒฝ์„ ํƒ์ง€ํ•  ๋•Œ ์ฃผ์˜ํ•  ์ 

    Vue๋Š” ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜ ์‚ญ์ œ๋œ ์†์„ฑ์— ๋ฐ˜์‘ํ˜•์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

    var vm = new Vue({
      data: {
        user: {
          name: 'John'
        }
      }
    })
    
    // `vm.name` is now reactive
    
    vm.email = john@email.com // `vm.email` is NOT reactive

    ์ด ๊ฒฝ์šฐ๋Š” Vue.set(object, key, value)๋‚˜ Object.assign()๋ฅผ ์ด์šฉํ•จ์œผ๋กœ์จ ๋ฐ˜์‘ํ˜• ์†์„ฑ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    Vue.set(vm.user, 'email', john@email.com);
    vm.user = Object.assign({}, vm.user, {
      email: john@email.com
    })
  16. v-for๋ฅผ ํŠน์ • ํšŸ์ˆ˜๋งŒํผ ๋ฐ˜๋ณตํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    v-for ์ง€์‹œ์ž์— ์ •์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ํŠน์ • ํšŸ์ˆ˜๋งŒํผ ๋ฐ˜๋ณตํ•ด ๋ Œ๋”๋ง ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <div>
      <span v-for="n in 20">{{ n }} </span>
    </div>

    ์ด ๊ฒฝ์šฐ 1๋ถ€ํ„ฐ 20๊นŒ์ง€ ์ˆซ์ž๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

  17. v-for๋กœ ํ…œํ”Œ๋ฆฟ์„ ๋ฐ˜๋ณตํ•˜๋Š” ๋ฐฉ๋ฒ•์€

    <template>์—์„œ v-if๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒƒ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ, <template>์—์„œ v-for ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <ul>
      <template v-for="todo in todos">
        <li>{{ todo.title }}</li>
        <li class="divider"></li>
      </template>
    </ul>
  18. ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    VueJS์—์„œ๋Š” ์ˆœ์ˆ˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ์œ ์‚ฌํ•˜๊ฒŒ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜์—์„œ $event ๋ณ€์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <button v-on:click="show('Welcome to VueJS world', $event)">
      Submit
    </button>
    
    methods: {
      show: function (message, event) {
        // now we have access to the native event
        if (event) event.preventDefault()
        console.log(message);
      }
    }
  19. Vue์—์„œ ์ด๋ฒคํŠธ ์ˆ˜์‹์–ด(Event modifier)๋ž€?

    ์ผ๋ฐ˜์ ์œผ๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๋‚ด๋ถ€์—์„œ event.preventDefault() ๋˜๋Š” event.stopPropagation()๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. Vue์˜ ๋ฉ”์†Œ๋“œ ๋‚ด๋ถ€์—์„œ๋„ ์ด ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, DOM์—์„œ ๋ฐœ์ƒํ•œ ์ด๋ฒคํŠธ์™€ ๋ฉ”์†Œ๋“œ์˜ ๋กœ์ง์€ ๋ณ„๊ฐœ๋กœ ๊ตฌ๋ถ„ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

    ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด, Vue๋Š” v-on ์ด๋ฒคํŠธ์— ์ด๋ฒคํŠธ ์ˆ˜์‹์–ด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ˆ˜์‹์–ด๋Š” ์ ์œผ๋กœ ํ‘œ์‹œ๋œ ์ ‘๋ฏธ์‚ฌ ์ž…๋‹ˆ๋‹ค.

    1. .stop
    2. .prevent
    3. .capture
    4. .self
    5. .once
    6. .passive

    .stop ์ˆ˜์‹์–ด๋ฅผ ์˜ˆ๋กœ ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

    <!-- the click event's propagation will be stopped -->
    <a v-on:click.stop="methodCall"></a>

    ์ˆ˜์‹์–ด๋Š” ์—ฐ์†ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <!-- modifiers can be chained -->
    <a v-on:click.stop.prevent="doThat"></a>
  20. ํ‚ค ์ˆ˜์‹์–ด(Key modifiers)๋ž€?

    Vue๋Š” ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ๋ฅผ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•ด v-on ์ง€์‹œ์ž์— ํ‚ค ์ˆ˜์‹์–ด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

    <!-- only call `vm.show()` when the `keyCode` is 13 -->
    <input v-on:keyup.13="show">

    ๋ชจ๋“  ํ‚ค ์ฝ”๋“œ๋ฅผ ์™ธ์šฐ๋Š” ๊ฒƒ์€ ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์—, Vue์—์„œ๋Š” ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ํ‚ค๋“ค์€ ๋ณ„์นญ์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

    1. .enter
    2. .tab
    3. .delete (โ€œDeleteโ€์™€ โ€œBackspaceโ€ ํฌํ•จ)
    4. .esc
    5. .space
    6. .up
    7. .down
    8. .left
    9. .right

    ์œ„ ์˜ˆ์‹œ์˜ ํ‚ค ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋ณ„์นญ์œผ๋กœ ๋‹ค์‹œ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <input v-on:keyup.enter="submit">
    // (OR)
    <!-- with shorthand notation-->
    <input @keyup.enter="submit">

    ํ‚ค ์ฝ”๋“œ ์ด๋ฒคํŠธ์˜ ์‚ฌ์šฉ์€ ์ตœ์‹  ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” ์ง€์›๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  21. ํ‚ค ์ˆ˜์‹์–ด๋ฅผ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    ์ „์—ญ config.keyCodes ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ํ‚ค ์ˆ˜์‹์–ด๋ฅผ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ๋ช‡ ๊ฐ€์ง€ ๊ทœ์น™๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.

    1. ์นด๋ฉœ ์ผ€์ด์Šค(camelCase)๋ฅผ ๋Œ€์‹  ์Œ๋”ฐ์˜ดํ‘œ๋กœ ๊ฐ์‹ธ์ง„ ์ผ€๋ฐฅ ์ผ€์ด์Šค(Kebab-case)๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    2. ๋ฐฐ์—ด์„ ์ด์šฉํ•ด ํ•œ ๋ฒˆ์— ์—ฌ๋Ÿฌ ๊ฐ’๋“ค์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    Vue.config.keyCodes = {
      f1: 112,
      "media-play-pause": 179,
      down: [40, 87]
    }
  22. ์‹œ์Šคํ…œ ์ˆ˜์‹์–ด ํ‚ค(System modifier key)๋ž€?

    Vue์—์„œ๋Š” ๋‹ค์Œ ์ˆ˜์‹์–ด๋ฅผ ์‚ฌ์šฉํ•ด ํ•ด๋‹น ์ˆ˜์‹์–ด ํ‚ค๊ฐ€ ๋ˆŒ๋Ÿฌ์ง„ ๊ฒฝ์šฐ์—๋งŒ ๋งˆ์šฐ์Šค ๋˜๋Š” ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    1. .ctrl
    2. .alt
    3. .shift
    4. .meta

    ์•„๋ž˜๋Š” ์ปจํŠธ๋กค ํ‚ค๊ฐ€ ๋ˆŒ๋ฆฐ ์ƒํƒœ์—์„œ ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ํ™œ์„ฑํ™” ํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

    <!-- Ctrl + Click -->
    <div @click.ctrl="doSomething">Do something</div>
  23. ๋งˆ์šฐ์Šค ๋ฒ„ํŠผ ์ˆ˜์‹์–ด(Mouse button modifier)๋ž€?

    Vue๋Š” ํŠน์ •ํ•œ ๋งˆ์šฐ์Šค ๋ฒ„ํŠผ์œผ๋กœ ๋ฐœ์ƒํ•œ ์ด๋ฒคํŠธ๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    1. .left
    2. .right
    3. .middle

    ๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ๋กœ .right๋ฅผ ์ด์šฉํ•œ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

     <button
       v-if="button === 'right'"
       v-on:mousedown.right="increment"
       v-on:mousedown.left="decrement"
     />
  24. v-model์˜ ์—ญํ• ์€?

    v-model ์ง€์‹œ์ž๋ฅผ ์ด์šฉํ•ด input, textarea, select ์—˜๋ฆฌ๋จผํŠธ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์–‘๋ฐฉํ–ฅ์œผ๋กœ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์˜ input ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์‚ดํŽด๋ณด์„ธ์š”.

    <input v-model="message" placeholder="Enter input here">
    <p>The message is: {{ message }}</p>

    v-model์€ ๋ชจ๋“  form ์—˜๋ฆฌ๋จผํŠธ์—์„œ HTML ์†์„ฑ(attribute)์œผ๋กœ ์„ ์–ธ๋œ value, checked ๊ทธ๋ฆฌ๊ณ  selected๋ฅผ ๋ฌด์‹œํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ๋Œ€์‹  Vue ์ธ์Šคํ„ด์Šค์—์„œ v-model๋กœ ๋ฐ”์ธ๋”ฉํ•œ ๊ฐ’์„ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ปดํฌ๋„ŒํŠธ์˜ data์—์„œ ์ดˆ๊ธฐ๊ฐ’์„ ์„ ์–ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  25. v-model์—์„œ ์ง€์›๋˜๋Š” ์ˆ˜์‹์–ด๋Š”?

    v-model ์ง€์‹œ์ž์—๋Š” ์„ธ ๊ฐ€์ง€ ์ˆ˜์‹์–ด๊ฐ€ ์ง€์›๋ฉ๋‹ˆ๋‹ค.

    1. lazy: ๊ธฐ๋ณธ์ ์œผ๋กœ, v-model์€ ํ•˜๋‚˜์˜ ํ‚ค ์ž…๋ ฅ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ๋งˆ๋‹ค data๊ฐ€ ์—…๋ฐ์ดํŠธ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” .lazy ์ˆ˜์‹์–ด๋ฅผ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค.

    <!-- synced after "change" instead of "input" -->
    <input v-model.lazy="msg" >

    2. number: v-model์— .number ์ˆ˜์‹์–ด๋ฅผ ๋ถ™์ด๋ฉด ์ž๋™์ ์œผ๋กœ ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์˜ ์ž๋ฃŒํ˜•์ด Number๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. HTML input ํƒœ๊ทธ์˜ ์†์„ฑ์ด type="number"์ผ์ง€๋ผ๋„ ๋ฐ˜ํ™˜๋˜๋Š” ๊ฐ’์˜ ์ž๋ฃŒํ˜•์€ ๋ฌธ์ž์—ด์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ˆซ์ž ์ž๋ฃŒํ˜•์ด ํ•„์š”ํ•˜๋‹ค๋ฉด .number ์ˆ˜์‹์–ด๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    <input v-model.number="age" type="number">

    3. trim: .trim ์ˆ˜์‹์–ด๋ฅผ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์—์„œ ์ฒ˜์Œ๊ณผ ๋์— ๋“ค์–ด์žˆ๋Š” ๊ณต๋ฐฑ์„ ์ž๋™์œผ๋กœ ์ œ๊ฑฐํ•ด์ค๋‹ˆ๋‹ค.

    <input v-model.trim="msg">
  26. ์ปดํฌ๋„ŒํŠธ(Component)๋ž€?

    ์ปดํฌ๋„ŒํŠธ๋ž€ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋ฉด์„œ ์ด๋ฆ„์ด ๋ช…๋ช…๋œ Vue ์ธ์Šคํ„ด์Šค์ž…๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋Š” Vue์ฒ˜๋Ÿผ data, computed, watch, methods, ๋ผ์ดํ”„์‚ฌ์ดํด ์˜ต์…˜์„ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” Vue์— ์ „์—ญ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

    // Define a new component called button-counter
    Vue.component('button-counter', {
      template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
      data: function () {
        return {
          count: 0
        }
      },
    })

    ์ด ์ปดํฌ๋„ŒํŠธ๋Š” ์ „์—ญ์œผ๋กœ ์„ ์–ธ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— Vue ์ธ์Šคํ„ด์Šค์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <div id="app">
      <button-counter></button-counter>
    </div>
    
    var vm = new Vue({ el: '#app' });
  27. props๋ž€?

    props๋Š” ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์˜ ์ •๋ณด๋ฅผ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋Š” ์‚ฌ์šฉ์ž ์ง€์ •์˜ ์†์„ฑ์ž…๋‹ˆ๋‹ค. ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ „๋‹ฌ๋˜๋Š” props๋Š” ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์˜ ์†์„ฑ์œผ๋กœ ์—ฌ๊ฒจ์ง€๋ฉฐ, ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” props ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ˆ˜์‹ ํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋˜๋Š” props๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์„ ์–ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    Vue.component('todo-item', {
      props: ['title'],
      template: '<h2>{{ title }}</h2>'
    })

    ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ props๊ฐ€ ๋“ฑ๋ก๋˜๊ณ  ๋‚˜๋ฉด, ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ์‚ฌ์šฉ์ž ์ง€์ • ์†์„ฑ์„ ์ด์šฉํ•ด ๊ฐ’์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <todo-item title="Learn Vue conceptsnfirst"></todo-item>
  28. ์ปดํฌ๋„ŒํŠธ์—์„œ ์—ฌ๋Ÿฌ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์“ฐ๋ ค๋ฉด?

    ํ…œํ”Œ๋ฆฟ์ด ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์—˜๋ฆฌ๋จผํŠธ๋“ค๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์„ ๋•Œ, ์ปดํฌ๋„ŒํŠธ์˜ ์ตœ์ƒ๋‹จ ํ…œํ”Œ๋ฆฟ์€ ๋ฐ˜๋“œ์‹œ ๋‹จ์ผ ์—˜๋ฆฌ๋จผํŠธ๋กœ ๊ฐ์‹ธ์ ธ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    <div class="todo-item">
      <h2>{{ title }}</h2>
      <div v-html="content"></div>
    </div>

    ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด, "Component template should contain exactly one root element..."๋ผ๋Š” ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

  29. ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ด๋ฒคํŠธ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ $event ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ด ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    Vue.component('todo-tem', {
      props: ['todo'],
      template: `
        <div class="todo-item">
          <h3>{{ todo.title }}</h3>
          <button v-on:click="$emit('increment-count', 1)">
            Add
          </button>
          <div v-html="todo.description"></div>
        </div>
      `
    })

    ์ด ๋•Œ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” v-on ์ง€์‹œ์ž๋ฅผ ์ด์šฉํ•ด ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ช…๋ช…ํ•œ ์ด๋ฒคํŠธ์™€ ๊ฐ’์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <ul v-for="todo in todos">
     <li>
       <todo-item
         v-bind:key="todo.id"
         v-bind:todo="todo"
         v-on:increment-count="total += 1">
       </todo-item>
     </li>
    </ul>
    <span> Total todos count is {{total}}</span>
  30. ์‚ฌ์šฉ์ž ์ •์˜์˜ input ์ปดํฌ๋„ŒํŠธ์—์„œ v-model์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฒ•์€?

    ์‚ฌ์šฉ์ž ์ •์˜ input ์ปดํฌ๋„ŒํŠธ์—์„œ๋„ v-model์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์˜ input์€ ์•„๋ž˜ ๊ทœ์น™๋“ค์„ ์ค€์ˆ˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    1. input์˜ value๋ฅผ props๋ฅผ ์ด์šฉํ•ด ๋ฐ”์ธ๋”ฉํ•ฉ๋‹ˆ๋‹ค.
    2. ์ƒˆ๋กœ์šด ๊ฐ’์ด ์ž…๋ ฅ๋˜๋Š” input ์ด๋ฒคํŠธ ๋ฐœ์ƒ ์‹œ, ํ•ด๋‹น ๊ฐ’์„ emitํ•˜์—ฌ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ด๋ฒคํŠธ๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
    Vue.component('custom-input', {
      props: ['value'],
      template: `
        <input
          v-bind:value="value"
          v-on:input="$emit('input', $event.target.value)"
        >
      `
    })

    ์ด ๊ฒฝ์šฐ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ v-model์„ ์ด์šฉํ•ด ๊ฐ’์„ ๋ฐ”์ธ๋”ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <custom-input v-model="searchInput"></custom-input>
  31. slots์ด๋ž€?

    Vue์—์„œ๋Š” <slot>์„ ์ด์šฉํ•ด ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์— ์‚ฌ์šฉ์ž ์ •์˜์˜ ์ปจํ…์ธ ๋ฅผ ์ง‘์–ด ๋„ฃ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์— <slot>์„ ์ด์šฉํ•ด ๋ฌธ๊ตฌ๋ฅผ ๋™์ ์œผ๋กœ ๋„ฃ์„ ์ˆ˜ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ด…์‹œ๋‹ค.

    Vue.component('alert', {
      template: `
        <div class="alert-box">
          <strong>Error!</strong>
          <slot></slot>
        </div>
      `
    })

    <alert> ํƒœ๊ทธ ์•ˆ์— ๋„ฃ์€ ๊ฐ’์€ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์˜ <slot>์˜ ์ปจํ…์ธ ๋กœ ๋“ค์–ด๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

    <alert>
      There is an issue with in application.
    </alert>
  32. ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ „์—ญ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ „์—ญ์œผ๋กœ ๋“ฑ๋กํ•˜๊ฒŒ ๋˜๋ฉด ๋ชจ๋“  Vue ์ธ์Šคํ„ด์Šค์—์„œ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋Š” Vue.component() ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์ „์—ญ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    Vue.component('my-component-name', {
      // ... options ...
    })

    Vue ์ธ์Šคํ„ด์Šค์— ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ „์—ญ ๋“ฑ๋กํ•ด๋ด…์‹œ๋‹ค.

    Vue.component('component-a', { /* ... */ })
    Vue.component('component-b', { /* ... */ })
    Vue.component('component-c', { /* ... */ })
    
    new Vue({ el: '#app' })

    ์œ„์˜ ์ปดํฌ๋„ŒํŠธ๋“ค์€ Vue ์ธ์Šคํ„ด์Šค ๋‚ด์—์„œ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <div id="app">
      <component-a></component-a>
      <component-b></component-b>
      <component-c></component-c>
    </div>

    ์ „์—ญ์œผ๋กœ ๋“ฑ๋กํ•œ ์ปดํฌ๋„ŒํŠธ๋“ค์€ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ๋„ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

  33. ์ปดํฌ๋„ŒํŠธ์˜ ์ง€์—ญ ๋“ฑ๋ก์ด ํ•„์š”ํ•œ ์ด์œ ๋Š”?

    ์ „์—ญ ๋“ฑ๋ก์œผ๋กœ ์ธํ•ด ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋นŒ๋“œ ์‹œ์— ์—ฌ์ „ํžˆ ๋‚จ์•„์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ถˆํ•„์š”ํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งŒ๋“ค์ฃ . ์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด, ์•„๋ž˜์™€ ๊ฐ™์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง€์—ญ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    1. ์šฐ์„  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
    var ComponentA = { /* ... */ }
    var ComponentB = { /* ... */ }
    var ComponentC = { /* ... */ }

    ์ง€์—ญ ๋“ฑ๋กํ•œ ์ปดํฌ๋„ŒํŠธ๋Š” ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์˜ ํ•˜์œ„์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ, components ์†์„ฑ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    var ComponentA = { /* ... */ }
    
    var ComponentB = {
      components: {
        'component-a': ComponentA
      },
      // ...
    }
    1. Vue ์ธ์Šคํ„ด์Šค์—์„œ components ์†์„ฑ์— ์‚ฌ์šฉํ•  ์ปดํฌ๋„ŒํŠธ๋“ค์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    new Vue({
      el: '#app',
      components: {
        'component-a': ComponentA,
        'component-b': ComponentB
      }
    })
  34. ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์—์„œ ์ „์—ญ ๋“ฑ๋ก๊ณผ ์ง€์—ญ ๋“ฑ๋ก์˜ ์ฐจ์ด์ ์€?

    ์ง€์—ญ ๋“ฑ๋ก์˜ ๊ฒฝ์šฐ, ๊ฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋””๋ ‰ํ† ๋ฆฌ์— ์ƒ์„ฑํ•˜๊ณ  ๊ฐ๊ฐ์˜ ์ปดํฌ๋„ŒํŠธ๋Š” ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ import ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ์ปดํฌ๋„ŒํŠธ C์—์„œ ์ปดํฌ๋„ŒํŠธ A์™€ B๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์„ค์ •์„ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    import ComponentA from './ComponentA'
    import ComponentB from './ComponentC'
    
    export default {
      components: {
        ComponentA,
        ComponentB
      }
    }

    ์œ„์˜ ๊ฒฝ์šฐ ์ปดํฌ๋„ŒํŠธ A์™€ ์ปดํฌ๋„ŒํŠธ B๋Š” ์ปดํฌ๋„ŒํŠธ C์˜ ํ…œํ”Œ๋ฆฟ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ์ „์—ญ ๋“ฑ๋ก์˜ ๊ฒฝ์šฐ, ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ๊ฐ์˜ ํŒŒ์ผ์—์„œ exportํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ webpack๊ณผ ๊ฐ™์€ ์œ ๋ช…ํ•œ ๋ฒˆ๋“ค๋Ÿฌ๋“ค์€ require.context๋ผ๋Š” ๋ฌธ๋ฒ•์„ ์ด์šฉํ•ด์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‰ฝ๊ฒŒ ์ „์—ญ์ ์œผ๋กœ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

    import Vue from 'vue'
    import upperFirst from 'lodash/upperFirst'
    import camelCase from 'lodash/camelCase'
    
    const requireComponent = require.context(
      // The relative path of the components folder
      './components',
      // Whether or not to look in subfolders
      false,
      // The regular expression used to match base component filenames
      /Base[A-Z]\w+\.(vue|js)$/
    )
    
    requireComponent.keys().forEach(fileName => {
      // Get component config
      const componentConfig = requireComponent(fileName)
    
      // Get PascalCase name of component
      const componentName = upperFirst(
        camelCase(
          // Strip the leading `./` and extension from the filename
          fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
        )
      )
    
      // Register component globally
      Vue.component(
        componentName,
        // Look for the component options on `.default`, which will
        // exist if the component was exported with `export default`,
        // otherwise fall back to module's root.
        componentConfig.default || componentConfig
      )
    })
  35. Prop ํƒ€์ž…์˜ ์ข…๋ฅ˜๋Š”?

    props์—๋Š” ํƒ€์ž…์„ ์ง€์ •ํ•  ์ˆ˜๋„, ์ง€์ •ํ•˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ ํƒ€์ž…์„ ์ง€์ •ํ•˜๋ฉด ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค์ด ํ•ด๋‹น ์ฝ”๋“œ์—์„œ ์ž˜๋ชป๋œ ํƒ€์ž…์˜ props๋ฅผ ๋„˜๊ฒจ์ฃผ๋Š” ์‹ค์ˆ˜๋ฅผ ์ค„์—ฌ์ฃผ๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ€๋Šฅํ•˜๋ฉด ํƒ€์ž…์„ ์ง€์ •ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

    props: {
      name: String,
      age: Number,
      isAuthenticated: Boolean,
      phoneNumbers: Array,
      address: Object
    }

    props ๊ฐ์ฒด์˜ ์†์„ฑ๊ณผ ๊ฐ’์„ ์„ ์–ธํ•จ์œผ๋กœ์„œ, ํƒ€์ž…์„ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  36. props์— ์˜ํ•œ ๋ฐ์ดํ„ฐ ํ๋ฆ„์€?

    ๋ชจ๋“  props๋Š” ํ•˜์œ„ ์†์„ฑ๊ณผ ์ƒ์œ„ ์†์„ฑ ์‚ฌ์ด์—์„œ ๋‹จ๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ์„ ํ˜•์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์ƒ์œ„ ์†์„ฑ์ด ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒƒ์€ ํ•˜์œ„ ์†์„ฑ์—๊ฒŒ ์ „๋‹ฌ๋˜์ง€๋งŒ, ๊ทธ ๋ฐ˜๋Œ€๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค. ์›์น™์ ์œผ๋กœ, ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฐ›์€ props์„ ์ˆ˜์ •ํ•ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค.

    ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ props ์ˆ˜์ •์˜ ํ•„์š”์„ฑ์„ ๋Š๋‚„ ์ˆ˜ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋Š”๋ฐ, ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    1. ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์˜ props๋Š” ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์˜ ์ดˆ๊ธฐ๊ฐ’ ์„ค์ •์—๋งŒ ์‚ฌ์šฉ๋˜๊ณ  ๊ทธ ์ดํ›„์—๋Š” ๋กœ์ปฌ ๋ฐ์ดํ„ฐ ์†์„ฑ์œผ๋กœ ํ™œ์šฉ๋˜๋Š” ๊ฒฝ์šฐ:

    ์ด ๊ฒฝ์šฐ, ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•  ์†์„ฑ์„ data์— ์„ ์–ธํ•˜๊ณ , ๊ทธ ๊ฐ’์„ props๋กœ ์ดˆ๊ธฐํ™”ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

    props: ['defaultUser'],
    data: function () {
      return {
        username: this.defaultUser
      }
    }
    1. ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ props๋กœ ์ „ํ•ด์ฃผ๋Š” ๊ฐ’์ด ์ˆ˜์ •๋˜๋Š” ๊ฒฝ์šฐ

    ์ด ๊ฒฝ์šฐ, ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ computed ์†์„ฑ์„ ์ด์šฉํ•ด props์˜ ๊ฐ’์ด ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ์‹ ๊ทœ ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    props: ['environment'],
    computed: {
      localEnvironment: function () {
        return this.environment.trim().toUpperCase()
      }
    }
  37. Props๊ฐ€ ์•„๋‹Œ ์†์„ฑ์€?

    props๊ฐ€ ์•„๋‹Œ ์†์„ฑ์ด๋ž€, ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌ๋˜๊ธฐ๋Š” ํ•˜์ง€๋งŒ ํ•ด๋‹น props๊ฐ€ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ •์˜๋˜์ง€๋Š” ์•Š์€ ์†์„ฑ์„ ๋งํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ data-tooltip ์†์„ฑ์„ ์š”๊ตฌํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ด…์‹œ๋‹ค. ์ด ์†์„ฑ์„ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ถ”๊ฐ€ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <custom-input data-tooltip="Enter your input" />

    ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ๋ถ€ํ„ฐ props๊ฐ€ ์•„๋‹Œ ์†์„ฑ์„ ๋„˜๊ฒจ์ฃผ๋ ค ํ•œ๋‹ค๋ฉด, ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ฐ™์€ ์ด๋ฆ„์„ ๊ฐ€์ง„ ์†์„ฑ์€ ๋ฎ์–ด์”Œ์›Œ์ง‘๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ class๋‚˜ style๊ฐ™์€ props๋Š” ์˜ˆ์™ธ๋กœ, ์ด ๊ฐ’๋“ค์€ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์™€ ํ•ฉ์ณ์ง‘๋‹ˆ๋‹ค.

    //Parent component
    <custom-input class="custom-class" />
    
    //Child component
    <input type="date" class="date-control">
  38. props๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    Vue์—์„œ๋Š” ํƒ€์ž…, ํ•„์ˆ˜ ์—ฌ๋ถ€, ๋””ํดํŠธ ๊ฐ’ ๋“ฑ props์˜ ์œ ํšจ์„ฑ ๊ฒ€์ฆ์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด props๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ๊ทœ์น™์ด ์†์„ฑ์œผ๋กœ ๋‹ด๊ธด ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

    Vue.component('user-profile', {
      props: {
        // Basic type check (`null` matches any type)
        age: Number,
        // Multiple possible types
        identityNumber: [String, Number],
        // Required string
        email: {
          type: String,
          required: true
        },
        // Number with a default value
        minBalance: {
          type: Number,
          default: 10000
        },
        // Object with a default value
        message: {
          type: Object,
          // Object or array defaults must be returned from
          // a factory function
          default: function () {
            return { message: 'Welcome to Vue' }
          }
        },
        // Custom validator function
        location: {
          validator: function (value) {
            // The value must match one of these strings
            return ['India', 'Singapore', 'Australia'].indexOf(value) !== -1
          }
        }
      }
    })
  39. ์ปดํฌ๋„ŒํŠธ์—์„œ v-model์„ ์‚ฌ์šฉ์ž ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    ์ผ๋ฐ˜์ ์ธ ์ปดํฌ๋„ŒํŠธ์—์„œ v-model ์ง€์‹œ์ž๋Š” value๋ฅผ props๋กœ ์‚ฌ์šฉํ•˜๊ณ  input์„ ์ด๋ฒคํŠธ๋กœ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ์ฒดํฌ ๋ฐ•์Šค๋‚˜ ๋ผ๋””์˜ค ๋ฒ„ํŠผ๊ฐ™์€ ์ผ๋ถ€ ์ž…๋ ฅ ํƒ€์ž…์€ ๋‹ค๋ฅธ ๋ชฉ์ ์œผ๋กœ value ์†์„ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” v-model์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

    Vue.component('custom-checkbox', {
      model: {
        prop: 'checked',
        event: 'change'
      },
      props: {
        checked: Boolean
      },
      template: `
        <input
          type="checkbox"
          v-bind:checked="checked"
          v-on:change="$emit('change', $event.target.checked)"
        >
      `
    })

    ์ด ์ปดํฌ๋„ŒํŠธ์—์„œ v-model์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <custom-checkbox v-model="selectFramework"></custom-checkbox>

    selectFramework ์†์„ฑ์€ props ์ค‘ checked๋กœ ๋„˜์–ด๊ฐˆ ๊ฒƒ์ด๊ณ , ์ฒดํฌ ๋ฐ•์Šค ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  40. ํŠธ๋žœ์ง€์…˜ ํšจ๊ณผ๋ฅผ ๋„ฃ์„ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€?

    Vue์—์„œ๋Š” ํ•ญ๋ชฉ๋“ค์ด DOM์—์„œ ์ถ”๊ฐ€, ๊ฐฑ์‹  ๋˜๋Š” ์‚ญ์ œ๋  ๋•Œ, ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ํŠธ๋žœ์ง€์…˜ ํšจ๊ณผ๋ฅผ ์ž…ํž ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    1. CSS ํŠธ๋žœ์ง€์…˜๊ณผ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์œ„ํ•œ ํด๋ž˜์Šค๋ฅผ ์ž๋™์œผ๋กœ ์ ์šฉ
    2. Animate.css์™€ ๊ฐ™์€ ์จ๋“œํŒŒํ‹ฐ CSS ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ†ตํ•ฉ
    3. ํŠธ๋žœ์ง€์…˜ ํ›… ์ค‘์— JavaScript๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ DOM์„ ์ง์ ‘ ์กฐ์ž‘
    4. Velocity.js์™€ ๊ฐ™์€ ์จ๋“œํŒŒํ‹ฐ JavaScript ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ†ตํ•ฉ
  41. Vue Router๋ž€?

    Vue Router๋Š” Vue์—์„œ ๋™์ž‘ํ•˜๋Š” ๊ณต์‹์ ์ธ ๋ผ์šฐํŒ… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

    1. ์ค‘์ฒฉ๋œ ๋ผ์šฐํŠธ/๋ทฐ ๋งคํ•‘
    2. ๋ชจ๋“ˆํ™”๋œ, ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜์˜ ๋ผ์šฐํ„ฐ ์„ค์ •
    3. ๋ผ์šฐํ„ฐ ํŒŒ๋ผ๋ฏธํ„ฐ, ์ฟผ๋ฆฌ, ์™€์ผ๋“œ์นด๋“œ
    4. Vue์˜ ํŠธ๋žœ์ง€์…˜ ์‹œ์Šคํ…œ์„ ์ด์šฉํ•œ ํŠธ๋žœ์ง€์…˜ ํšจ๊ณผ
    5. ์„ธ๋ฐ€ํ•œ ๋„ค๋น„๊ฒŒ์ด์…˜ ์ปจํŠธ๋กค
    6. active CSS ํด๋ž˜์Šค๋ฅผ ์ž๋™์œผ๋กœ ์ถ”๊ฐ€ํ•ด์ฃผ๋Š” ๋งํฌ
    7. HTML5 ํžˆ์Šคํ† ๋ฆฌ ๋ชจ๋“œ ๋˜๋Š” ํ•ด์‹œ ๋ชจ๋“œ(IE9์—์„œ ์ž๋™์œผ๋กœ ํด๋ฐฑ)
    8. ์‚ฌ์šฉ์ž ์ •์˜ ๊ฐ€๋Šฅํ•œ ์Šคํฌ๋กค ๋™์ž‘
  42. Vue Router๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    Vue๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, ์‰ฝ๊ฒŒ Vue Router๋ฅผ ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    Step 1: ๋จผ์ € ํ…œํ”Œ๋ฆฟ์—์„œ <router-link>ํƒœ๊ทธ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    
    <div id="app">
      <h1>Welcome to Vue routing app!</h1>
      <p>
        <!-- use router-link component for navigation using `to` prop. It rendered as an `<a>` tag -->
        <router-link to="/home">Home</router-link>
        <router-link to="/services">Services</router-link>
      </p>
      <!-- route outlet in which component matched by the route will render here -->
      <router-view></router-view>
    </div>

    Step 2: main.js์—์„œ Vue์™€ Vue ๋ผ์šฐํ„ฐ๋ฅผ importํ•˜๊ณ  Vue.use()ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

    import Vue from 'vue';
    import VueRouter from 'vue-router';
    
    Vue.use(VueRouter)

    Step 3: ๋ผ์šฐํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•˜๊ฑฐ๋‚˜ importํ•ฉ๋‹ˆ๋‹ค.

    const Home = { template: '<div>Home</div>' }
    const Services = { template: '<div>Services</div>' }

    Step 4: ๋ผ์šฐํŠธ๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ๋ผ์šฐํŠธ๋Š” ๋ฐ˜๋“œ์‹œ ์ปดํฌ๋„ŒํŠธ์™€ ๋งคํ•‘๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    const routes = [
      { path: '/home', component: Home },
      { path: '/services', component: Services }
    ]

    Step 5: routes ์˜ต์…˜๊ณผ ํ•จ๊ป˜ router ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

    const router = new VueRouter({
      routes // short for `routes: routes`
    })

    Step 6: ๋ฃจํŠธ Vue ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค๊ณ  mountํ•ฉ๋‹ˆ๋‹ค.

    const app = new Vue({
      router
    }).$mount('#app')

    ์ด์ œ Vue ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋‹ค๋ฅธ ํŽ˜์ด์ง€(Home, Services)๋กœ ๋„ค๋น„๊ฒŒ์ดํŠธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  43. ๋™์  ๋ผ์šฐํŠธ ๋งค์นญ์ด๋ž€?

    ์ฃผ์–ด์ง„ ํŒจํ„ด์„ ๊ฐ€์ง„ ๋ผ์šฐํŠธ๋ฅผ ๋™์ผํ•œ ์ปดํฌ๋„ŒํŠธ์— ๋งคํ•‘ํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ž์ฃผ ์žˆ์Šต๋‹ˆ๋‹ค. ๋™์  ์„ธ๊ทธ๋จผํŠธ๋ฅผ ์ด์šฉํ•ด /user/john/post/123๋‚˜ /user/jack/post/235์™€ ๊ฐ™์ด ๋งคํ•‘๋œ URL์„ ๊ฐ€์ง€๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ด…์‹œ๋‹ค.

    const User = {
      template: '<div>User {{ $route.params.name }}, PostId: {{ route.params.postid }}</div>'
    }
    
    const router = new VueRouter({
      routes: [
        // dynamic segments start with a colon
        { path: '/user/:name/post/:postid', component: User }
      ]
    })
  44. ๋ผ์šฐํ„ฐ params๋ฅผ ๋ฐ˜์‘์ ์œผ๋กœ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์€?

    ๋งค๊ฐœ ๋ณ€์ˆ˜์™€ ํ•จ๊ป˜ ๋ผ์šฐํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ ํ•ด์•ผํ•  ์ ์€ ์‚ฌ์šฉ์ž๊ฐ€ /user/foo์—์„œ /user/bar๋กœ ์ด๋™ํ•  ๋•Œ ๋™์ผํ•œ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๊ฐ€ ์žฌ์‚ฌ์šฉ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‘ ๋ผ์šฐํŠธ ๋ชจ๋‘ ๋™์ผํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๋ฏ€๋กœ ์ด์ „ ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ญ์ œ ํ•œ ๋‹ค์Œ ์ƒˆ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ๋ณด๋‹ค ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Š” ๋˜ํ•œ ์ปดํฌ๋„ŒํŠธ์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด ํ›…์ด ํ˜ธ์ถœ๋˜์ง€ ์•Š์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

    ๋™์ผํ•œ ์ปดํฌ๋„ŒํŠธ์˜ params ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋ฐ˜์‘ํ•˜๋ ค๋ฉด $route ๊ฐ์ฒด๋ฅผ ๋ณด๋ฉด๋ฉ๋‹ˆ๋‹ค.

    1. watch์—์„œ $route ๊ด€์ฐฐํ•˜๊ธฐ:
    const User = {
      template: '<div>User {{ $route.params.name }} </div>',
      watch: {
        '$route' (to, from) {
          // react to route changes...
        }
      }
    }
    1. beforeRouteUpdate ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ:
    const User = {
      template: '<div>User {{ $route.params.name }} </div>',
      beforeRouteUpdate (to, from, next) {
        // react to route changes and then call next()
      }
    }

    beforeRouteEnter ๊ฐ€๋“œ์—์„œ๋Š” this์— ์ ‘๊ทผํ•  ๊ถŒํ•œ์ด ์—†๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์„ธ์š”. ๋Œ€์‹ , next ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์ธ์Šคํ„ด์Šค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  45. ๋ผ์šฐํŠธ์˜ ์šฐ์„  ์ˆœ์œ„๋Š”?

    ๋™์ผํ•œ URL์ด ์—ฌ๋Ÿฌ ๋ผ์šฐํŠธ์™€ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ์ผ์น˜ํ•˜๋Š” ์šฐ์„  ์ˆœ์œ„๋Š” ๋ผ์šฐํŠธ ์ •์˜์˜ ์ˆœ์„œ์— ๋”ฐ๋ผ ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค. ์ฆ‰, ๊ฒฝ๋กœ๊ฐ€ ๋” ๋จผ์ € ์ •์˜ ๋ ์ˆ˜๋ก ์šฐ์„  ์ˆœ์œ„๊ฐ€ ๋†’์•„์ง‘๋‹ˆ๋‹ค.

    const router = new VueRouter({
           routes: [
             // dynamic segments start with a colon
             { path: '/user/:name', component: User } // This route gets higher priority
             { path: '/user/:name', component: Admin }
             { path: '/user/:name', component: Customer }
           ]
         })
  46. ์ค‘์ฒฉ๋œ ๋ผ์šฐํŠธ๋ž€?

    ์ผ๋ฐ˜์ ์œผ๋กœ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์—ฌ๋Ÿฌ ๋‹จ๊ณ„์˜ ์ค‘์ฒฉ๋œ ์ปดํฌ๋„ŒํŠธ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. URL์˜ ์„ธ๊ทธ๋จผํŠธ ์—ญ์‹œ ์ค‘์ฒฉ๋œ ์ปดํฌ๋„ŒํŠธ์˜ ํŠน์ • ๊ตฌ์กฐ์™€ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค. ์ค‘์ฒฉ๋œ ์•„์›ƒ๋ ›์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๋ ค๋ฉด VueRouter ์ƒ์„ฑ์ž์—์„œ config๋กœ children์„ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    ํ”„๋กœํ•„๊ณผ ํฌ์ŠคํŠธ๋“ค์ด ์ƒ๋Œ€์ ์ธ ๊ฒฝ๋กœ๋กœ ์„ค์ •๋œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค์–ด๋ด…์‹œ๋‹ค. ๋งค์นญ๋˜๋Š” ํ•˜์œ„ ๋ผ์šฐํŠธ๊ฐ€ ์—†์„ ๊ฒฝ์šฐ์— ๋ Œ๋”๋ง๋˜๋Š” ๋ผ์šฐํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    const router = new VueRouter({
      routes: [
        { path: '/user/:id', component: User,
          children: [
            {
              // UserProfile will be rendered inside User's <router-view> when /user/:id/profile is matched
              path: 'profile',
              component: UserProfile
            },
            {
              // UserPosts will be rendered inside User's <router-view> when /user/:id/posts is matched
              path: 'posts',
              component: UserPosts
            },
              // UserHome will be rendered inside User's <router-view> when /user/:id is matched
            {  path: '',
               component: UserHome },
          ]
        }
      ]
    })
  47. ์‹ฑ๊ธ€ ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ๋ž€?

    ์•„๋งˆ ํ•˜๋‚˜์˜ ํŽ˜์ด์ง€์—์„œ HTML, CSS, JavaScript์„ ๋‹ค๋ฅธ ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌํ•ด ๊ด€๋ฆฌํ•ด๋ณธ ๊ฒฝํ—˜์ด ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‹ฑ๊ธ€ ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ํ…œํ”Œ๋ฆฟ๊ณผ ์Šคํƒ€์ผ, ๋กœ์ง๋“ค์„ ํ•˜๋‚˜์˜ ํŒŒ์ผ์— ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

    <template>
        <div>
            <h1>Welcome {{ name }}!</h1>
        </div>
    </template>
    
    <script>
        module.exports = {
           data: function() {
               return {
                   name: 'John'
               }
           }
        }
    </script>
    
    <style scoped>
        h1 {
            color: #34c779;
            padding: 3px;
        }
    </style>
  48. ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ(separation of concerns)์ด๋ž€?

    ์ฃผ๋ชฉํ•ด์•ผ ํ•  ์ค‘์š”ํ•œ ์ ์€ ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ๊ฐ€ ํŒŒ์ผ ํƒ€์ž… ๋ถ„๋ฆฌ์™€ ๊ฐ™์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ˜„๋Œ€์ ์ธ UI ๊ฐœ๋ฐœ์—์„œ ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ์„œ๋กœ ์–ฝํ˜€์žˆ๋Š” ์„ธ ๊ฐœ์˜ ๊ฑฐ๋Œ€ํ•œ ๋ ˆ์ด์–ด๋กœ ๋‚˜๋ˆ„๋Š” ๋Œ€์‹ , ๋Š์Šจํ•˜๊ฒŒ ๊ฒฐํ•ฉ ๋œ ์ปดํฌ๋„ŒํŠธ๋กœ ๋‚˜๋ˆ„๊ณ  ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์ด ๋” ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ํ…œํ”Œ๋ฆฟ, ๋กœ์ง ๋ฐ ์Šคํƒ€์ผ์ด ๋ณธ์งˆ์ ์œผ๋กœ ๊ฒฐํ•ฉ๋˜์–ด ๋ฐฐ์น˜๋˜๋ฉด ์ปดํฌ๋„ŒํŠธ์˜ ์‘์ง‘๋ ฅ๊ณผ ์œ ์ง€ ๋ณด์ˆ˜์„ฑ์ด ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.

    ์‹ฑ๊ธ€ ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ์•„์ด๋””์–ด๊ฐ€ ๋งˆ์Œ์— ๋“ค์ง€ ์•Š๋”๋ผ๋„ JavaScript์™€ CSS๋ฅผ ๋ณ„๋„์˜ ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ํ•ซ ๋ฆฌ๋กœ๋“œ ๋ฐ ์‚ฌ์ „ ์ปดํŒŒ์ผ ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <template>
      <div>This section will be pre-compiled and hot reloaded</div>
    </template>
    <script src="./my-component.js"></script>
    <style src="./my-component.css"></style>
  49. ์‹ฑ๊ธ€ ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ๋Š” ์™œ ํ•„์š”ํ• ๊นŒ?

    ๋ณต์žกํ•œ ํ”„๋กœ์ ํŠธ์˜ ๊ฒฝ์šฐ ๋˜๋Š” ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ JavaScript ๊ธฐ๋ฐ˜์ธ ๊ฒฝ์šฐ ๋‹จ์ ์ด ๋ถ„๋ช…ํ•ด์ง‘๋‹ˆ๋‹ค. ์‹ฑ๊ธ€ ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฌธ์ œ์ ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    1. ์ „์—ญ ์ •์˜ ๋ชจ๋“  ๊ตฌ์„ฑ ์š”์†Œ์— ๋Œ€ํ•ด ๊ณ ์œ ํ•œ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋„๋ก ๊ฐ•์š”๋ฉ๋‹ˆ๋‹ค.
    2. ๋ฌธ์ž์—ด ํ…œํ”Œ๋ฆฟ ๊ตฌ๋ฌธ ๊ฐ•์กฐ๊ฐ€ ์•ฝํ•ด ์—ฌ๋Ÿฌ ์ค„๋กœ ๋œ HTML์— ๋ณด๊ธฐ ์•ˆ์ข‹์€ ์Šฌ๋ž˜์‹œ๊ฐ€ ๋งŽ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
    3. CSS ์ง€์› ์—†์Œ HTML ๋ฐ JavaScript๊ฐ€ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ชจ๋“ˆํ™” ๋˜์–ด ์žˆ์œผ๋‚˜ CSS๊ฐ€ ๋น ์ ธ ์žˆ๋Š” ๊ฒƒ์„ ๋งํ•ฉ๋‹ˆ๋‹ค.
    4. ๋นŒ๋“œ ๋‹จ๊ณ„ ์—†์Œ Pug (์ด์ „์˜ Jade) ๋ฐ Babel๊ณผ ๊ฐ™์€ ์ „์ฒ˜๋ฆฌ๊ธฐ๊ฐ€ ์•„๋‹Œ HTML ๋ฐ ES5 JavaScript๋กœ ์ œํ•œ๋ฉ๋‹ˆ๋‹ค.

    ์‹ฑ๊ธ€ ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ๋Š” JavaScript ๊ธฐ๋ฐ˜์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์ ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด, ๋ณ„๋„์˜ .vue ํ™•์žฅ์ž์˜ ํŒŒ์ผ๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

  50. filter๋ž€?

    filter๋Š” ํ…์ŠคํŠธ ํ˜•์‹ํ™”๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด ํ•„ํ„ฐ๋“ค์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ‘œํ˜„์‹์— ํŒŒ์ดํ”„(|) ๊ธฐํ˜ธ์™€ ํ•จ๊ป˜ ์ถ”๊ฐ€๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€ ๊ฒฝ์šฐ์—์„œ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    1. ์ค‘๊ด„ํ˜ธ ๋ณด๊ฐ„๋ฒ•
    2. v-bind ํ‘œํ˜„์‹

    ์ฒซ ๊ธ€์ž๋ฅผ ๋Œ€๋ฌธ์ž๋กœ ๋งŒ๋“œ๋Š” ๋กœ์ปฌ ํ•„ํ„ฐ๋ฅผ ์ •์˜ํ•ด๋ด…์‹œ๋‹ค.

    filters: {
      capitalize: function (value) {
        if (!value) return ''
        value = value.toString()
        return value.charAt(0).toUpperCase() + value.slice(1)
      }
    }

    ์ด ํ•„ํ„ฐ๋ฅผ ์ค‘๊ด„ํ˜ธ ๋ณด๊ฐ„๋ฒ• ๋˜๋Š” v-bind ํ‘œํ˜„์‹ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <!-- in mustaches -->
    {{ username | capitalize }}
    
    <!-- in v-bind -->
    <div v-bind:id="username | capitalize"></div>
  51. filter๋ฅผ ์ „์—ญ์  ๋˜๋Š” ์ง€์—ญ์ ์œผ๋กœ ๋งŒ๋“œ๋Š” ๋ฒ•์€?

    1. ์ง€์—ญ ํ•„ํ„ฐ(Local filters): ์ง€์—ญ ํ•„ํ„ฐ๋Š” ์ปดํฌ๋„ŒํŠธ์˜ ์˜ต์…˜์—์„œ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ, ํ•„ํ„ฐ๋Š” ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
    filters: {
      capitalize: function (value) {
        if (!value) return ''
        value = value.toString()
        return value.charAt(0).toUpperCase() + value.slice(1)
      }
    }
    1. ์ „์—ญ ํ•„ํ„ฐ(Global filters): Vue ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์ „์— ์ „์—ญ์ ์œผ๋กœ ํ•„ํ„ฐ๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ Vue ์ธ์Šคํ„ด์Šค ๋‚ด์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์—์„œ ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    Vue.filter('capitalize', function (value) {
      if (!value) return ''
      value = value.toString()
      return value.charAt(0).toUpperCase() + value.slice(1)
    })
    
    new Vue({
      // ...
    })
  52. filter๋ฅผ ์—ฐ์†ํ•ด ์“ฐ๋Š” ๋ฐฉ๋ฒ•์€?

    ์ผ๋ฐ˜์ ์œผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด, ํ‘œํ˜„์‹์—์„œ ํ•„ํ„ฐ ๋’ค์— ๋˜ ๋‹ค๋ฅธ ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    {{ message | filterA | filterB | filterC ... }}

    ๊ฐ๊ฐ์˜ ํ•„ํ„ฐ๋Š” ํŒŒ์ดํ”„(|)๋กœ ๊ตฌ๋ถ„๋˜๋ฉฐ, message๋Š” filterA์˜ ๊ฒฐ๊ณผ๊ฐ€ filterB์˜ ์˜ํ–ฅ์„ ๋ฐ›๊ณ , ๊ทธ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ค์‹œ filterC์˜ ์˜ํ–ฅ์„ ๋ฐ›์Šต๋‹ˆ๋‹ค.

    ์˜ˆ๋ฅผ ๋“ค์–ด, ๋‚ ์งœ ํ˜•์‹์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•œ ๋’ค ๋Œ€๋ฌธ์ž๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    {{ birthday | dateFormat | uppercase }}
  53. filter์— ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์„๊นŒ?

    ํ•„ํ„ฐ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์—, ์•„๋ž˜์™€ ๊ฐ™์ด ๋‘ ๊ฐœ ์ด์ƒ์˜ ์ธ์ˆ˜๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    {{ message | filterA('arg1', arg2) }}

    ์—ฌ๊ธฐ์„œ filterA๋Š” ์„ธ ๊ฐœ์˜ ์ธ์ˆ˜๋ฅผ ๋ฐ›๋Š” ํ•จ์ˆ˜๋กœ ์ •์˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค. message์˜ ๊ฐ’์€ ์ฒซ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋  ๊ฒƒ์ด๋ฉฐ, ์ˆœ์ˆ˜ ๋ฌธ์ž์—ด์ธ 'arg1'์€ ๋‘๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋  ๊ฒƒ์ด๋ฉฐ, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ‘œํ˜„์‹์ธ arg2๋Š” ํ‘œํ˜„์‹์ด ์‹คํ–‰๋œ ์ดํ›„์— ์„ธ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

    {{ 2 | exponentialStrength(10) }} // prints 2 power 10 = 1024
  54. ํ”Œ๋Ÿฌ๊ทธ์ธ์ด๋ž€?

    ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์ „์—ญ ์ˆ˜์ค€ ๊ธฐ๋Šฅ์„ Vue ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

    1. ์ „์—ญ ๋ฉ”์†Œ๋“œ ๋˜๋Š” ์†์„ฑ ์ถ”๊ฐ€(<vue-custom-element>)
    2. ํ•˜๋‚˜ ์ด์ƒ์˜ ๊ธ€๋กœ๋ฒŒ ์—์…‹ ์ถ”๊ฐ€(์ง€์‹œ์ž, ํ•„ํ„ฐ, ํŠธ๋žœ์ง€์…˜)
    3. ์ „์—ญ ๋ฏน์Šค์ธ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ ์˜ต์…˜(vuex)
    4. Vue.prototype๋ฅผ ์ด์šฉํ•ด Vue์— ์ธ์Šคํ„ด์Šค ๋ฉ”์†Œ๋“œ๋ฅผ ์ถ”๊ฐ€
    5. ์œ„์˜ ๊ธฐ๋Šฅ๊ณผ ํ•จ๊ป˜ ์ž์ฒด API๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(vue-router)
  55. ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์€?

    ํ”Œ๋Ÿฌ๊ทธ์ธ์—์„œ๋Š” install ๋ฉ”์†Œ๋“œ๋ฅผ ์ •์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์†Œ๋“œ๋Š” ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋กœ Vue ์ƒ์„ฑ์ž์™€ ์™ธ๋ถ€์—์„œ ์„ค์ • ๊ฐ€๋Šฅํ•œ ์˜ต์…˜์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ๋ฐ›์Šต๋‹ˆ๋‹ค.

    MyPlugin.install = function (Vue, options) {
      // 1. add global method or property
      Vue.myGlobalMethod = function () {
        // some logic ...
      }
    
      // 2. add a global asset
      Vue.directive('my-directive', {
        bind (el, binding, vnode, oldVnode) {
          // some logic ...
        }
        ...
      })
    
      // 3. inject some component options
      Vue.mixin({
        created: function () {
          // some logic ...
        }
        ...
      })
    
      // 4. add an instance method
      Vue.prototype.$myMethod = function (methodOptions) {
        // some logic ...
      }
    }
  56. ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    Vue.use() ์ „์—ญ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ์ƒ์„ฑ์ž new Vue()๋กœ Vue ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์ „์— ํ˜ธ์ถœ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    // calls `MyPlugin.install(Vue, { someOption: true })`
    Vue.use(MyPlugin)
    
    new Vue({
      //... options
    })
  57. ๋ฏน์Šค์ธ์ด๋ž€?

    Mixins๋Š” Vue ์ปดํฌ๋„ŒํŠธ์— ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ธฐ๋Šฅ์„ ๋ฐฐํฌํ•˜๋Š” ์œ ์—ฐํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๋ฏน์Šค์ธ์— ์กด์žฌํ•˜๋Š” ๊ธฐ๋Šฅ๋“ค์€ ํ˜ธ์ถœ๋œ ์ปดํฌ๋„ŒํŠธ์˜ ๊ธฐ๋Šฅ๋“ค๊ณผ ํ•ฉ์ณ์ง‘๋‹ˆ๋‹ค.

    mixin ๊ฐ์ฒด๋Š” ๋ชจ๋“  ๊ตฌ์„ฑ ์š”์†Œ ์˜ต์…˜์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—์„œ ์žฌ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋Š” created ๋ผ์ดํ”„์‚ฌ์ดํด ํ›…์„ ๊ฐ€์ง„ ๋ฏน์Šค์ธ์„ ์ž‘์„ฑํ•ด๋ด…์‹œ๋‹ค.

    const myMixin = {
      created(){
        console.log("Welcome to Mixins!")
      }
    }
    var app = new Vue({
      el: '#root',
      mixins: [myMixin]
    })

    Note: ์—ฌ๋Ÿฌ ๋ฏน์Šค์ธ์€ ๋ฐฐ์—ด์˜ ํ˜•ํƒœ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  58. ์ „์—ญ ๋ฏน์Šค์ธ์ด๋ž€?

    Vue ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์— ๋™์ผํ•œ ์˜ต์…˜์ด๋‚˜ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•ด ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ, ์ „์—ญ ๋ฏน์Šค์ธ์„ ํ™œ์šฉํ•ด Vue์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    Vue.mixin({
       created(){
         console.log("Write global mixins")
       }
    })
    
    new Vue({
      el: '#app'
    })

    ์œ„์˜ ์ „์—ญ ๋ฏน์Šค์ธ์€ ํ•ด๋‹น Vue ์ธ์Šคํ„ด์Šค์—์„œ ๊ฐ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ๋งˆ๋‹ค created ํ›…์—์„œ ๋กœ๊ทธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ์ฆ‰ ๋ชจ๋“  ๋‹จ์ผ Vue ์ธ์Šคํ„ด์Šค์— ์˜ํ–ฅ์„ ์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ์ ๊ฒŒ ์ด์šฉํ•˜๊ณ  ์‹ ์ค‘ํ•˜๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  59. CLI ํ™˜๊ฒฝ์—์„œ ๋ฏน์Šค์ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฒ•์€?

    Vue CLI๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ๋ฏน์Šค์ธ์€ ์ผ๋ฐ˜์ ์œผ๋กœ /src/mixins ๋””๋ ‰ํ† ๋ฆฌ์—์„œ .jsํŒŒ์ผ๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. export ํ‚ค์›Œ๋“œ๋กœ ์™ธ๋ถ€์— ๋‚ด๋ณด๋‚ธ๋‹ค๋Š” ๊ฒƒ์„ ์„ ์–ธํ•ด์•ผ ํ•˜๋ฉฐ ์‚ฌ์šฉํ•  Vue ์ปดํฌ๋„ŒํŠธ์—์„œ import ํ‚ค์›Œ๋“œ๋กœ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  60. ๋ฏน์Šค์ธ์˜ ์˜ต์…˜์ด ์ปดํฌ๋„ŒํŠธ์˜ ์˜ต์…˜๊ณผ ์ถฉ๋Œํ•œ๋‹ค๋ฉด?

    ๋ฏน์Šค์ธ๊ณผ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ถฉ๋Œํ•˜๋Š” ์˜ต์…˜์ด ์žˆ๋‹ค๋ฉด, ์˜ต์…˜์€ ๋ช‡ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด ์ถฉ๋Œํ•˜๋Š” ์˜ต์…˜์„ ๋ณ‘ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

    1. data๋Š” ์žฌ๊ท€์ ์œผ๋กœ ๋ณ‘ํ•ฉํ•˜๋˜, ์ถฉ๋Œ๋˜๋Š” ์†์„ฑ์€ ์ปดํฌ๋„ŒํŠธ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์šฐ์„ ์ ์œผ๋กœ ๋ณ‘ํ•ฉ๋ฉ๋‹ˆ๋‹ค.
    var mixin = {
      data: function () {
        return {
          message: 'Hello, this is a Mixin'
        }
      }
     }
    new Vue({
      mixins: [mixin],
      data: function () {
        return {
          message: 'Hello, this is a Component'
        }
      },
      created: function () {
        console.log(this.$data); // => { message: "Hello, this is a Component'" }
      }
    })
    1. ๋ผ์ดํ”„์‚ฌ์ดํด ํ›… ํ•จ์ˆ˜๋Š” ๋ฏน์Šค์ธ ํ•จ์ˆ˜๊ฐ€ ๋จผ์ € ์‹คํ–‰๋˜๊ณ , ๊ทธ ๋‹ค์Œ์— ์ปดํฌ๋„ŒํŠธ์˜ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
    const myMixin = {
      created(){
        console.log("Called from Mixin")
      }
    }
    
    new Vue({
      el: '#root',
      mixins:[myMixin],
      created(){
        console.log("Called from Component")
      }
    })
    
    //Called from Mixin
    //Called from Component
    1. methods, components, directives ์—ญ์‹œ ์žฌ๊ท€์ ์œผ๋กœ ๋ณ‘ํ•ฉํ•˜๋˜, ์ด๋Ÿฌํ•œ ๊ฐ์ฒด์— ์ถฉ๋Œํ•˜๋Š” ํ‚ค๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ ์ปดํฌ๋„ŒํŠธ์˜ ์˜ต์…˜์ด ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค.
    var mixin = {
      methods: {
        firstName: function () {
          console.log('John')
        },
        contact: function () {
          console.log('+65 99898987')
        }
      }
    }
    
    var vm = new Vue({
      mixins: [mixin],
      methods: {
        lastName: function () {
          console.log('Murray')
        },
        contact: function () {
          console.log('+91 893839389')
        }
      }
    })
    
    vm.firstName() // "John"
    vm.lastName() // "Murray"
    vm.contact() // "+91 893839389"
  61. ๋ฏน์Šค์ธ์˜ ๋ณ‘ํ•ฉ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉ์ž ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    Vue์—์„œ๋Š” ์‚ฌ์šฉ์ž ์ง€์ • ์˜ต์…˜์„ ๋ณ‘ํ•ฉํ•  ๋•Œ ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ธฐ์กด ๊ฐ’์„ ๋ฎ์–ด๋Š” ๋ฐฉ๋ฒ•์„ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์‚ฌ์šฉ์ž ์ •์˜์˜ ๋กœ์ง์„ ์‚ฌ์šฉํ•ด ์ปค์Šคํ…€ ์˜ต์…˜์„ ๋ณ‘ํ•ฉํ•˜๋ ค๋ฉด,Vue.config.optionMergeStrategies์— ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

    Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) {
      // return mergedVal
    }

    ๋” ๊ณ ๊ธ‰ ์˜ˆ์ œ๋Š” Vuex์˜ 1.x ๋ณ‘ํ•ฉ ์ „๋žต์—์„œ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    const merge = Vue.config.optionMergeStrategies.computed
    Vue.config.optionMergeStrategies.vuex = function (toVal, fromVal) {
      if (!toVal) return fromVal
      if (!fromVal) return toVal
      return {
        getters: merge(toVal.getters, fromVal.getters),
        state: merge(toVal.state, fromVal.state),
        actions: merge(toVal.actions, fromVal.actions)
      }
    }
  62. ์‚ฌ์šฉ์ž ์ •์˜ ์ง€์‹œ์ž(Custom directive)๋ž€?

    ์ง€์‹œ์ž๋Š” DOM ์—˜๋ฆฌ๋จผํŠธ์— ๋ถ€์ฐฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ช…๋ น์–ด์ž…๋‹ˆ๋‹ค. ์œ„์—์„œ ๋ณธ ๊ฒƒ์ฒ˜๋Ÿผ v-๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•ด Vue๊ฐ€ ์ด ๋ช…๋ น์–ด๋ฅผ ์ธ์‹ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ํ•˜์œ„ ์ˆ˜์ค€์˜ DOM์„ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•ด ์ง์ ‘ ์ ‘๊ทผํ•ด์•ผ ํ•  ํ•„์š”๊ฐ€ ์žˆ์„ ๋•Œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

    ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋“œ๋  ๋•Œ input์— ์ž๋™์œผ๋กœ ํฌ์ปค์‹ฑ๋˜๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ์ง€์‹œ์ž๋ฅผ ์ „์—ญ์œผ๋กœ ๋งŒ๋“ค์–ด๋ด…์‹œ๋‹ค.

    // Register a global custom directive called `v-focus`
    Vue.directive('focus', {
      // When the bound element is inserted into the DOM...
      inserted: function (el) {
        // Focus the element
        el.focus()
      }
    })

    ์ด์ œ ์ด ์ง€์‹œ์ž๋Š” v-focus๋ผ๋Š” ๋ฌธ๋ฒ•๊ณผ ํ•จ๊ป˜ ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ์—์„œ๋“  ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <input v-focus>
  63. ์ง€์‹œ์ž๋ฅผ ์ง€์—ญ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    ์ง€์‹œ์ž๋ฅผ ์ง€์—ญ ๋“ฑ๋กํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” directives ์˜ต์…˜์„ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค.

    directives: {
      focus: {
        // directive definition
        inserted: function (el) {
          el.focus()
        }
      }
    }

    ์ด ์ง€์‹œ์ž๋Š” ์„ ์–ธ๋œ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์—์„œ๋งŒ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <input v-focus>
  64. ์ง€์‹œ์ž์— ์˜ํ•ด ์ œ๊ณต๋˜๋Š” ๋ผ์ดํ”„ ์‚ฌ์ดํด ํ›…์€?

    ์ง€์‹œ์ž ๊ฐ์ฒด๊ฐ€ ๋“ฑ๋ก๋  ๋•Œ ๋ช‡ ๊ฐœ์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด ํ›…์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

    1. bind: ์ง€์‹œ์ž๊ฐ€ ์ฒ˜์Œ ์—˜๋ฆฌ๋จผํŠธ์— ๋ถ€์ฐฉ๋  ๋•Œ ํ•œ ๋ฒˆ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
    2. inserted: ์ง€์‹œ์ž๊ฐ€ ๋ถ€์ฐฉ๋œ ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ DOM์— ์‚ฝ์ž…๋˜์—ˆ์„ ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
    3. update: ํ•ด๋‹น ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์—…๋ฐ์ดํŠธ ๋  ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์•„์ง ํ•˜์œ„ ์—˜๋ฆฌ๋จผํŠธ๋Š” ์—…๋ฐ์ดํŠธ ๋˜์ง€ ์•Š์€ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.
    4. componentUpdated: ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๊นŒ์ง€ ์—…๋ฐ์ดํŠธ ๋œ ์ƒํƒœ์ผ ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
    5. unbind: ์ง€์‹œ์ž๊ฐ€ ์—˜๋ฆฌ๋จผํŠธ์—์„œ๋ถ€ํ„ฐ ์‚ญ์ œ๋  ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

    Note: ์œ„์˜ ํ›…์—์„œ๋Š” ํŠน์ •ํ•œ ์ „๋‹ฌ์ธ์ž(Argument)๋ฅผ ๋ฐ›๋Š”๋‹ค.

  65. ๋””๋ ‰ํ‹ฐ๋ธŒ ํ›…์˜ ์ „๋‹ฌ์ธ์ž๋Š”?

    ๋ชจ๋“  ํ›…์—์„œ๋Š” ์ „๋‹ฌ์ธ์ž๋กœ el, binding์™€ vnode๋ฅผ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ์™€ ํ•จ๊ป˜, update์™€ componentUpdatedํ›…์—์„œ๋Š” ์ƒˆ ๊ฐ’๊ณผ ์ด์ „ ๊ฐ’์„ ๋น„๊ตํ•˜๊ธฐ ์œ„ํ•ด oldVnode๋ฅผ ์ถ”๊ฐ€์ ์œผ๋กœ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

    1. el: ํ•ด๋‹น ์ง€์‹œ์ž๊ฐ€ ๋ถ€์ฐฉ๋œ ์—˜๋ฆฌ๋จผํŠธ๋กœ, ์ด๋ฅผ ์ด์šฉํ•ด DOM์„ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    2. binding: ์•„๋ž˜์˜ ์†์„ฑ์„ ๊ฐ€์ง„ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.
      1. name: ์ง€์‹œ์ž์˜ ์ด๋ฆ„์œผ๋กœ, v- ์ ‘๋‘์‚ฌ๊ฐ€ ์ œ๊ฑฐ๋œ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.
      2. value: ์ง€์‹œ์ž์—์„œ ์ „๋‹ฌ ๋ฐ›์€ ๊ฐ’์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ v-my-directive="1 + 1"๋ผ๋ฉด 2๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
      3. oldValue: ์ด์ „ ๊ฐ’์œผ๋กœ, update์™€ componentUpdatedํ›…์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ์•„๋‹Œ์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
      4. expression: ๋ฌธ์ž์—ด๋กœ ๋ฐ”์ธ๋”ฉ๋œ ํ‘œํ˜„์‹์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ v-my-directive="1 + 1"๋ผ๋ฉด "1 + 1"์ด ๋ฉ๋‹ˆ๋‹ค..
      5. arg: ์ง€์‹œ์ž์˜ ์ „๋‹ฌ์ธ์ž์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ v-my-directive:foo๋ผ๋ฉด "foo"๊ฐ€ ๋ฉ๋‹ˆ๋‹ค..
      6. modifiers: ์ˆ˜์‹์–ด๊ฐ€ ํฌํ•จ๋œ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ v-my-directive.foo.bar๋ผ๋ฉด { foo: true, bar: true }๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
    3. vnode: Vue์˜ ์ปดํŒŒ์ผ๋Ÿฌ์— ์˜ํ•ด ์ƒ์„ฑ๋œ ๊ฐ€์ƒ ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค.
    4. oldVnode: ์ด ์ „์˜ ๊ฐ€์ƒ ๋…ธ๋“œ๋กœ, update์™€ componentUpdatedํ›…์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    custom-directives

  66. ์ง€์‹œ์ž์— ์—ฌ๋Ÿฌ ๊ฐ’๋“ค์„ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    ์ง€์‹œ์ž๋Š” ์œ ํšจํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ‘œํ˜„์‹์€ ๋ชจ๋‘ ์ˆ˜์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ง€์‚ฌ์ž์— ์—ฌ๋Ÿฌ ๊ฐ’๋“ค์„ ์ „๋‹ฌํ•˜๋ ค๋ฉด, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์„ ์ด์šฉํ•ด ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <div v-avatar="{ width: 500, height: 400, url: 'path/logo', text: 'Iron Man' }"></div>

    ์ด์ œ v-avatar ์ง€์‹œ์ž๋ฅผ ์ „์—ญ์œผ๋กœ ์„ค์ •ํ•ด๋ด…์‹œ๋‹ค.

    Vue.directive('avatar', function (el, binding) {
      console.log(binding.value.width) // 500
      console.log(binding.value.height)  // 400
      console.log(binding.value.url) // path/logo
      console.log(binding.value.text)  // "Iron Man"
    })
  67. ์ง€์‹œ์ž ํ›…์—์„œ ํ•จ์ˆ˜ ์•ฝ์–ด๋Š”?

    ๋“œ๋ฌธ ๊ฒฝ์šฐ์ง€๋งŒ, ๋‹ค๋ฅธ ํ›…๊ณผ๋Š” ์ƒ๊ด€์—†์ด bind๋‚˜ update ํ›…์—์„œ ๊ฐ™์€ ๋™์ž‘์„ ํ•˜๊ธฐ ์›ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—๋Š” ํ•จ์ˆ˜ ์•ฝ์–ด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    Vue.directive('theme-switcher', function (el, binding) {
      el.style.backgroundColor = binding.value
    })
  68. render ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š”?

    ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ Vue์˜ ํ…œํ”Œ๋ฆฟ์„ ์ด์šฉํ•ด HTML์„ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ input์ด๋‚˜ slot์˜ ๊ฐ’์„ ์ด์šฉํ•ด ๋™์ ์ธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, ์ผ๋ถ€ ํŠน๋ณ„ํ•œ ๊ฒฝ์šฐ์—๋Š” JavaScript๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋•Œ render ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, renderํ•จ์ˆ˜๋Š” JavaScript๋กœ ์ž‘์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํ™˜๊ฒฝ์„ ์˜จ์ „ํžˆ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  69. render ํ•จ์ˆ˜๋ž€?

    render ํ•จ์ˆ˜๋Š” createElement๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋กœ ๋ฐ›์•„ ๊ฐ€์ƒ ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๋‚ด๋ถ€์ ์œผ๋กœ Vue์˜ ํ…œํ”Œ๋ฆฟ์€ ๋นŒ๋“œ ํƒ€์ž„์—์„œ render ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์ปดํŒŒ์ผํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ํ…œํ”Œ๋ฆฟ์€ render ํ•จ์ˆ˜๋ฅผ ๋ฌธ๋ฒ•์ ์œผ๋กœ ๋ณด๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด ๋†“์€ ๊ฒƒ์— ๊ฐ€๊น์Šต๋‹ˆ๋‹ค.

    <div> ํƒœ๊ทธ๋ฅผ ๊ฐ๊ฐ ํ…œํ”Œ๋ฆฟ๊ณผ render ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์ž‘์„ฑํ•ด๋ด…์‹œ๋‹ค. ํ…œํ”Œ๋ฆฟ์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <template>
     <div :class="{'is-rounded': isRounded}">
       <p>Welcome to Vue render functions</p>
     </div>
    </template>

    ์œ„์˜ ํ…œํ”Œ๋ฆฟ์„ render ํ•จ์ˆ˜๋กœ ์ž‘์„ฑํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    render: function (createElement) {
       return createElement('div', {
         'class': {
             'is-rounded': this.isRounded
         }
       }, [
         createElement('p', 'Welcome to Vue render functions')
       ]);
      },
  70. createElement ํ•จ์ˆ˜๋ž€?

    createElement ํ•จ์ˆ˜๋Š” ๋ช‡ ๊ฐ€์ง€์˜ ์•ฝ์†๋œ ์ „๋‹ฌ์ธ์ž๋ฅผ ๋ฐ›๋Š”๋ฐ, ์ด๋ฅผ ์ด์šฉํ•ด ํ…œํ”Œ๋ฆฟ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋Šฅ์„ JavaScript ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    // @returns {VNode}
    createElement(
      // An HTML tag name, component options, or async function resolving to one of these.
      // Type is {String | Object | Function}
      // Required.
      'div',
    
      // A data object corresponding to the attributes you would use in a template.
      //Type is {Object}
      // Optional.
      {
          // Normal HTML attributes
          attrs: {
            id: 'someId'
          },
          // Component props
          props: {
            myProp: 'somePropValue'
          },
          // DOM properties
          domProps: {
            innerHTML: 'This is some text'
          },
          // Event handlers are nested under `on`
          on: {
              click: this.clickHandler
            },
          // Similar to `v-bind:style`, accepting either a string, object, or array of objects.
           style: {
              color: 'red',
              fontSize: '14px'
           },
           //Similar to `v-bind:class`, accepting either a string, object, or array of strings and objects.
            class: {
               classsName1: true,
               classsName2: false
            },
            ....
      },
    
      // Children VNodes, built using `createElement()`, or using strings to get 'text VNodes'.
      // Type is {String | Array}
      // Optional.
      [
        'Learn about createElement arguments.',
        createElement('h1', 'Headline as a child virtual node'),
        createElement(MyComponent, {
          props: {
            someProp: 'This is a prop value'
          }
        })
      ]
    )

    ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๊ณต์‹ ๋ฌธ์„œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  71. ๊ฐ€์ƒ ๋…ธ๋“œ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€?

    ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์˜ ๋ชจ๋“  ๊ฐ€์ƒ ๋…ธ๋“œ(VNodes)๋Š” ๊ณ ์œ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์ง์ ‘ ๊ฐ€์ƒ ๋…ธ๋“œ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๊ฐ™์€ ์—˜๋ฆฌ๋จผํŠธ๋‚˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ๋ฐ˜๋ณตํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋ฉด, ํŒฉํ† ๋ฆฌ ํŒจํ„ด์„ ์ด์šฉํ•ด ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    ์•„๋ž˜์˜ render ํ•จ์ˆ˜๋Š” h1 ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์„ธ ๋ฒˆ ๋ฐ˜๋ณตํ•˜๋ ค ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์œ ํšจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

    render: function (createElement) {
      var myHeadingVNode = createElement('h1', 'This is a Virtual Node')
      return createElement('div', [
        myHeadingVNode, myHeadingVNode, myHeadingVNode
      ])
    }

    ํŒฉํ† ๋ฆฌ ํŒจํ„ด์„ ์ด์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

    render: function (createElement) {
      return createElement('div',
        Array.apply(null, { length: 3 }).map(function () {
          return createElement('h1', 'This is a Virtual Node')
        })
      )
    }
  72. render ํ•จ์ˆ˜์™€ ํ…œํ”Œ๋ฆฟ์„ ๋น„๊ตํ•œ๋‹ค๋ฉด?

    Vue์—์„œ HTML์„ ์ž‘์„ฑํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋˜๋Š” ํ…œํ”Œ๋ฆฟ๊ณผ render ํ•จ์ˆ˜๋ฅผ ๋น„๊ตํ•ด๋ด…์‹œ๋‹ค.

    ํ…œํ”Œ๋ฆฟ(Templates) ๋ Œ๋” ํ•จ์ˆ˜(Render function)
    v-if์™€ v-for๋ฅผ ์ด์šฉํ•ด ์กฐ๊ฑด๋ฌธ/๋ฐ˜๋ณต๋ฌธ ์‹คํ–‰ JavaScript์˜ if else๋ฌธ๊ณผ map ๋ฉ”์†Œ๋“œ๋กœ ์กฐ๊ฑด๋ฌธ/๋ฐ˜๋ณต๋ฌธ ์‹คํ–‰
    v-model๋กœ ์–‘๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ ๋ฐ”์ธ๋”ฉ๊ณผ ์ด๋ฒคํŠธ๋ฅผ ์ง์ ‘ ์„ค์ •
    Capture ์ด๋ฒคํŠธ ์ˆ˜์‹์–ด๋Š” .passive, .capture, .once, .capture.once, .once.capture &, !, ~, ~!
    ์ด๋ฒคํŠธ ์ˆ˜์‹์–ด์™€ ํ‚ค ์ˆ˜์‹์–ด: .stop, .prevent, .self, keys(.enter, .13) and Modifiers Keys(.ctrl, .alt, .shift, .meta) JavaScript๋กœ ํ•ด๊ฒฐ, event.stopPropagation(), event.preventDefault(), if (event.target !== event.currentTarget) return, if (event.keyCode !== 13) return, if (!event.ctrlKey) return
    ์Šฌ๋กฏ ์†์„ฑ ํ™œ์šฉ ๋ Œ๋” ํ•จ์ˆ˜์˜ this.$slots์™€ this.$scopedSlots ํ™œ์šฉ
  73. ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ(Functional component)๋ž€?

    ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋Š” context๋ฅผ ํ†ตํ•ด ์ „๋‹ฌ๋ฐ›์€ ์ •๋ณด๋กœ๋งŒ ์ƒ์„ฑ๋˜๋Š” ๊ฐ„๋‹จํ•œ ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค.

    1. ์ƒํƒœ ์—†์Œ(Stateless): ์ฆ‰ data๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค
    2. ์ธ์Šคํ„ด์Šค ์—†์Œ(Instanceless): ์ฆ‰ this๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค

    ์ด ๊ฒฝ์šฐ, functional: true ์†์„ฑ์„ ์ด์šฉํ•ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•จ์ˆ˜ํ˜•์œผ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    Vue.component('my-component', {
      functional: true,
      // Props are optional
      props: {
        // ...
      },
      // To compensate for the lack of an instance,
      // we are now provided a 2nd context argument.
      render: function (createElement, context) {
        // ...
      }
    })
  74. Vue์™€ React์˜ ๊ณตํ†ต์ ์€?

    1. ๋‘ ํ”„๋ ˆ์ž„์›Œํฌ ๋ชจ๋‘ ๊ฐ€์ƒ DOM ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    2. ๋ฐ˜์‘์ ์ด๊ณ  ์กฐํ•ฉ ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
    3. ์ฝ”์–ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—๋งŒ ์ง‘์ค‘ํ•˜๊ณ  ์žˆ๊ณ , ๋ผ์šฐํŒ… ๋ฐ ์ƒํƒœ ๊ด€๋ฆฌ์™€ ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋ถ€๊ฐ€์ ์œผ๋กœ ์žˆ์Šต๋‹ˆ๋‹ค.
  75. Vue์™€ React์˜ ์ฐจ์ด์ ์€?

    ํŠน์ง• Vue React
    ํƒ€์ž… JavaScript MVC ํ”„๋ ˆ์ž„์›Œํฌ JavaScript ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
    ํ”Œ๋žซํผ ์›น์„ ์šฐ์„ ์ ์œผ๋กœ ์›น๊ณผ ๋„ค์ดํ‹ฐ๋ธŒ ๋ชจ๋‘
    ๋ณต์žก๋„ ์ƒ๋Œ€์ ์œผ๋กœ ๊ฐ„๋‹จ ์ƒ๋Œ€์ ์œผ๋กœ ๋ณต์žก
    ๋นŒ๋“œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ Vue-cli CRA (Create-React-App)
  76. Vue๊ฐ€ React์— ๋น„ํ•ด ๋‚˜์€ ์ ์€?

    1. ๊ฐ€๋ณ๊ณ  ๋น ๋ฆ…๋‹ˆ๋‹ค.
    2. ํ…œํ”Œ๋ฆฟ์ด ๊ฐœ๋ฐœ ๊ณผ์ •์„ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.
    3. JSX์— ๋น„ํ•ด ๊ฐ€๋ฒผ์šด JavaScript ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  77. React๊ฐ€ Vue์— ๋น„ํ•ด ๋‚˜์€ ์ ์€?

    1. ํฐ ๊ทœ๋ชจ์˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ ์—ฐํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    2. ํ…Œ์ŠคํŠธ๊ฐ€ ์‰ฝ์Šต๋‹ˆ๋‹ค.
    3. ๋ชจ๋ฐ”์ผ ์•ฑ ์ œ์ž‘์—๋„ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.
    4. ์ƒํƒœ๊ณ„๊ฐ€ ํฌ๊ณ  ํ’๋ถ€ํ•ฉ๋‹ˆ๋‹ค.
  78. Vue์™€ AngularJS์˜ ์ฐจ์ด์ ์€?

    Vue์˜ ๊ฐœ๋ฐœ ์ดˆ๊ธฐ ๋‹จ๊ณ„์—์„œ AngularJS๋ฅผ ์ฐธ๊ณ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—, Vue์™€ AngularJS์˜ ๋ฌธ๋ฒ•์€ ์ƒ๋‹นํžˆ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ฐจ์ด์  ์—ญ์‹œ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

    ํŠน์ง• Vue AngularJS
    ๋ณต์žก๋„ ๋ฐฐ์šฐ๊ธฐ ์‰ฌ์šด API์™€ ๋””์ž์ธ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๊ฝค ํฌ๊ณ  ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๋“ฑ์˜ ์ง€์‹ ํ•„์š”
    ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ์–‘๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ ๋‹จ๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ
    ์ดˆ๊ธฐ ๋ฆด๋ฆฌ์ฆˆ 2014 2016
    ๋ชจ๋ธ ๊ฐ€์ƒ DOM ๊ธฐ๋ฐ˜ MVC
    ์ž‘์„ฑ๋œ ์–ธ์–ด JavaScript TypeScript
  79. ๋™์  ์ปดํฌ๋„ŒํŠธ๋ž€?

    <component> ํƒœ๊ทธ์—์„œ v-bind:is๋กœ ๋ฐ”์ธ๋”ฉ๋œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋™์ ์œผ๋กœ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    new Vue({
      el: '#app',
      data: {
        currentPage: 'home'
      },
      components: {
        home: {
          template: "<p>Home</p>"
        },
        about: {
          template: "<p>About</p>"
        },
        contact: {
          template: "<p>Contact</p>"
        }
      }
    })

    ์ด์ œ ํ…œํ”Œ๋ฆฟ์—์„œ <component> ํƒœ๊ทธ์— ๋ฐ”์ธ๋”ฉ ๋  ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <div id="app">
       <component v-bind:is="currentPage">
           <!-- component changes when currentPage changes! -->
           <!-- output: Home -->
       </component>
    </div>
  80. keep-alive ํƒœ๊ทธ๋ž€?

    <keep-alive>๋Š” ์ปดํฌ๋„ŒํŠธ์˜ ์ƒํƒœ๋ฅผ ๋ณด์กดํ•ด์„œ ์žฌ ๋ Œ๋”๋ง์„ ๋ง‰์•„์ฃผ๋Š” ์ถ”์ƒ ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋™์ ์ธ ์ปดํฌ๋„ŒํŠธ๋ฅผ <keep-alive> ํƒœ๊ทธ๋กœ ๊ฐ์‹ผ๋‹ค๋ฉด, ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๋ฅผ ์—†์• ์ง€ ์•Š๊ณ  ๋ฉ”๋ชจ๋ฆฌ์— ์œ ์ง€ํ•ด ๋ณด์กดํ•ฉ๋‹ˆ๋‹ค.

    <!-- Inactive components will be cached! -->
    <keep-alive>
      <component v-bind:is="currentTabComponent"></component>
    </keep-alive>

    ๋งŒ์•ฝ ์กฐ๊ฑด๋ฌธ์ด ์žˆ๋‹ค๋ฉด, ํ•ด๋‹น ์กฐ๊ฑด์˜ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋งŒ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.

    <!-- multiple conditional children -->
    <keep-alive>
      <comp-a v-if="a > 1"></comp-a>
      <comp-b v-else></comp-b>
    </keep-alive>

    Note: <keep-alive>๋Š” DOM์— ๋ Œ๋”๋ง ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  81. ๋น„๋™๊ธฐ ์ปดํฌ๋„ŒํŠธ(Async component)๋ž€?

    ๋Œ€๊ทœ๋ชจ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—์„œ๋Š” ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ๋” ์ž‘์€ ๋ฉ์–ด๋ฆฌ๋กœ ๋‚˜๋ˆ„๊ณ  ์‹ค์ œ๋กœ ํ•„์š”ํ•  ๋•Œ๋งŒ ์„œ๋ฒ„์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋กœ๋“œํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. Vue๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ ์ •์˜๋ฅผ ๋น„๋™๊ธฐ์‹์œผ๋กœ ํ•ด๊ฒฐํ•˜๋Š” ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    Vue.component('async-webpack-example', function (resolve, reject) {
      // Webpack automatically split your built code into bundles which are loaded over Ajax requests.
      require(['./my-async-component'], resolve)
    })

    Vue๋Š” Vue๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜์–ด์•ผ ํ•  ๋•Œ๋งŒ ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚ค๊ณ , ์ดํ›„์˜ ๋‚˜์ค‘์— ์žˆ์„ ๋ฆฌ๋ Œ๋”๋ง์„ ์œ„ํ•ด ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œํ•ฉ๋‹ˆ๋‹ค.

  82. ๋น„๋™๊ธฐ ์ปดํฌ๋„ŒํŠธ ํŒฉํ† ๋ฆฌ ํŒจํ„ด์ด๋ž€?

    ๋น„๋™๊ธฐ ์ปดํฌ๋„ŒํŠธ ํŒฉํ† ๋ฆฌ๋Š” ๋‹ค์Œ ํ˜•ํƒœ์˜ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    const AsyncComponent = () => ({
      // The component to load (should be a Promise)
      component: import('./MyComponent.vue'),
      // A component to use while the async component is loading
      loading: LoadingComponent,
      // A component to use if the load fails
      error: ErrorComponent,
      // Delay before showing the loading component. Default: 200ms.
      delay: 200,
      // The error component will be displayed if a timeout is
      // provided and exceeded. Default: Infinity.
      timeout: 3000
    })
  83. ์ธ๋ผ์ธ ํ…œํ”Œ๋ฆฟ(inline templates)์ด๋ž€?

    ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์— inline-template ์†์„ฑ์ด ์กด์žฌํ•  ๋•Œ, ์ปดํฌ๋„ŒํŠธ๋Š” ๋‚ด๋ถ€ ์ปจํ…์ธ ๋ฅผ ํ…œํ”Œ๋ฆฟ์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ณด๋‹ค ์œ ์—ฐํ•œ ํ…œํ”Œ๋ฆฟ ์ž‘์„ฑ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

    <my-component inline-template>
       <div>
           <h1>Inline templates</p>
           <p>Treated as component component owne content</p>
       </div>
    </my-component>

    Note: inline-template์€ ํ…œํ”Œ๋ฆฟ์˜ ๋ฒ”์œ„๋ฅผ ์ถ”๋ก ํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ template ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ .vue ํŒŒ์ผ์˜ template ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์— ํ…œํ”Œ๋ฆฟ์„ ์ •์˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  84. X-Templates์ด๋ž€?

    ํ…œํ”Œ๋ฆฟ๋ฅผ ์ •์˜ํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ text/x-template ์œ ํ˜•์˜ ์Šคํฌ๋ฆฝํŠธ ์—˜๋ฆฌ๋จผํŠธ ๋‚ด๋ถ€์˜ ID๋กœ ํ…œํ”Œ๋ฆฟ์„ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

    <script type="text/x-template" id="script-template">
      <p>Welcome to X-Template feature</p>
    </script>
    Vue.component('x-template-example', {
      template: '#script-template'
    })
  85. ์žฌ๊ท€ ์ปดํฌ๋„ŒํŠธ(recursive components)๋ž€?

    ์ปดํฌ๋„ŒํŠธ๋Š” ์ž์‹ ์˜ ํ…œํ”Œ๋ฆฟ์—์„œ ์ž๊ธฐ ์ž์‹ ์„ ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    Vue.component('recursive-component', {
      template: `<!--Invoking myself!-->
                 <recursive-component></recursive-component>`
    });

    ์žฌ๊ท€ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ธ”๋กœ๊ทธ์˜ ๋ง๊ธ€์ด๋‚˜ ๋ฉ”๋‰ด์ฒ˜๋Ÿผ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์™€ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋™๋“ฑํ•œ ๊ธฐ๋Šฅ์„ ํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

    Note: ์œ„์™€ ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ๋Š” ์ตœ๋Œ€ ์Šคํƒ ํฌ๊ธฐ ์ดˆ๊ณผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ์žฌ๊ท€ ํ˜ธ์ถœ์ด ์กฐ๊ฑด๋ถ€์ธ์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  86. ์ปดํฌ๋„ŒํŠธ ์‚ฌ์ด์˜ ์ˆœํ™˜ ์ฐธ์กฐ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€?

    ๋ณต์žกํ•œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ Vue ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์„œ๋กœ๊ฐ€ ์„œ๋กœ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์žˆ๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ A์™€ ์ปดํฌ๋„ŒํŠธ B๊ฐ€ ์„œ๋กœ ์ˆœํ™˜ ์ฐธ์กฐ๋ฅผ ํ•˜๊ณ  ์žˆ๋Š” ์ƒํ™ฉ์„ ์‚ดํŽด๋ด…์‹œ๋‹ค.

    //ComponentA
    <div>
      <component-b >
    </div>
    //ComponentB
    <div>
      <component-b >
    </div>

    ์ด๋Ÿฐ ๊ฒฝ์šฐ๋Š” beforeCreate ๋ผ์ดํ”„ ์‚ฌ์ดํด ํ›… ์‹œ์ ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋“ฑ๋กํ•˜๊ฑฐ๋‚˜, ์›นํŒฉ์˜ ๋น„๋™๊ธฐ import๋ฅผ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

    Solution1:

    beforeCreate: function () {
     this.$options.components.componentB = require('./component-b.vue').default
    }

    Solution2:

    components: {
     componentB: () => import('./component-b.vue')
    }
  87. CSP ํ™˜๊ฒฝ์—์„œ Vue ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋นŒ๋“œํ•˜๋Š” ๋ฒ•์€?

    Google ํฌ๋กฌ ์•ฑ๊ณผ ๊ฐ™์€ ์ผ๋ถ€ ํ™˜๊ฒฝ์—์„œ๋Š” CSP(์ปจํ…์ธ  ๋ณด์•ˆ ์ •์ฑ…)๋ฅผ ์ ์šฉํ•˜์—ฌ ํ‘œํ˜„์‹์„ ํ‰๊ฐ€ํ•˜๋Š” ๋ฐ new Function() ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ „์ฒด ๋นŒ๋“œ๋Š” ์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ…œํ”Œ๋ฆฟ์„ ์ปดํŒŒ์ผํ•˜๋ฏ€๋กœ ์ด๋Ÿฌํ•œ ํ™˜๊ฒฝ์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

    ๋ฐ˜๋ฉด ๋Ÿฐํƒ€์ž„ ์ „์šฉ ๋นŒ๋“œ๋Š” CSP์™€ ์™„๋ฒฝํ•˜๊ฒŒ ํ˜ธํ™˜๋ฉ๋‹ˆ๋‹ค. Webpack + vue-loader ๋˜๋Š” Browserify + vueify๋กœ ๋Ÿฐํƒ€์ž„ ์ „์šฉ ๋นŒ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ํ…œํ”Œ๋ฆฟ์€ CSP ํ™˜๊ฒฝ์—์„œ ์™„๋ฒฝํ•˜๊ฒŒ ์ž‘๋™ํ•˜๋Š” render ํ•จ์ˆ˜๋กœ ๋ฏธ๋ฆฌ ์ปดํŒŒ์ผ๋ฉ๋‹ˆ๋‹ค.

  88. ์ „์ฒด ๋นŒ๋“œ์™€ ๋Ÿฐํƒ€์ž„ ๋นŒ๋“œ์˜ ์ฐจ์ด์ ์€?

    1. ์ „์ฒด ๋นŒ๋“œ(Full): ์ปดํŒŒ์ผ๋Ÿฌ์™€ ๋Ÿฐํƒ€์ž„ ๋นŒ๋“œ๋ฅผ ๋™์‹œ์— ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ํ…œํ”Œ๋ฆฟ์„ ์ž‘์„ฑํ•œ ๊ฒฝ์šฐ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

    2. ๋Ÿฐํƒ€์ž„ ๋นŒ๋“œ(Runtime): Vue ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ๊ณผ render ํ•จ์ˆ˜, ๊ฐ€์ƒ ๋”์„ ํฌํ•จํ•˜๊ณ  ์žˆ์ง€๋งŒ ์ปดํŒŒ์ผ๋Ÿฌ ๋นŒ๋“œ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  89. Vue์˜ ๋นŒ๋“œ ์ข…๋ฅ˜๋Š”?

    ํƒ€์ž… UMD CommonJS ES Module (for bundlers) ES Module (for browsers)
    ์ „์ฒด ๋นŒ๋“œ vue.js vue.common.js vue.esm.js vue.esm.browser.js
    ๋Ÿฐํƒ€์ž„ ๋นŒ๋“œ vue.runtime.js vue.runtime.common.js vue.runtime.esm.js NA
    ์ „์ฒด ๋นŒ๋“œ (๋ฐฐํฌ ๋ชจ๋“œ) vue.min.js NA NA vue.esm.browser.min.js
    ๋Ÿฐํƒ€์ž„ ๋นŒ๋“œ (๋ฐฐํฌ ๋ชจ๋“œ) vue.runtime.min.js NA NA NA
  90. ์›นํŒฉ์—์„œ Vue ์„ค์ •์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    alias๋ฅผ ์ด์šฉํ•ด Vue๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    module.exports = {
      // ...
      resolve: {
        alias: {
          'vue$': 'vue/dist/vue.esm.js' // 'vue/dist/vue.common.js' for webpack 1
        }
      }
    }
  91. Vue ์ปดํŒŒ์ผ๋Ÿฌ์˜ ๋ชฉ์ ์€?

    Vue๋Š” ์ปดํŒŒ์ผ๋Ÿฌ๋ฅผ ์ด์šฉํ•ด ํ…œํ”Œ๋ฆฟ์„ render ํ•จ์ˆ˜๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

    // this requires the compiler
    new Vue({
      template: '<div>{{ message }}</div>'
    })
    
    // this does not
    new Vue({
      render (h) {
        return h('div', this.message)
      }
    })
  92. DevTool์ด๋ž€?

    DevTool์€ Vue ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‚ฌ์šฉ์ž ์นœํ™”์ ์ธ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋””๋ฒ„๊ทธ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ฃผ๋Š” ๋ธŒ๋ผ์šฐ์ € ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์ž…๋‹ˆ๋‹ค.

    Note: Vue ํŽ˜์ด์ง€๊ฐ€ ๋ฐฐํฌ ๋ชจ๋“œ์ผ ๊ฒฝ์šฐ์—๋Š” DevTool๋กœ ๋””๋ฒ„๊ทธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

  93. Vue์˜ ๋ธŒ๋ผ์šฐ์ € ์ง€์›์€?

    ECMAScript5๋ฅผ ์ง€์›ํ•˜๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋™์ž‘ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. IE8 ์ดํ•˜์˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  94. CDN์œผ๋กœ Vue๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    Vue๋Š” jsdelivr, unpkg, cdnjs์—์„œ ์ œ๊ณตํ•˜๋Š” CDN์„ ์ด์šฉํ•ด์„œ๋„ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์ดˆ๊ธฐ ๊ธฐํš, ํ•™์Šต์šฉ์œผ๋กœ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.7/dist/vue.js"></script>
    <script type="module">
      import Vue from 'https://cdn.jsdelivr.net/npm/vue@2.6.7/dist/vue.esm.browser.js'
    </script>

    Note: ๋ฒ„์ „ ์ •๋ณด๋ฅผ ์ง€์šฐ๋ฉด ํ•ญ์ƒ ์ตœ์‹  ๋ฒ„์ „์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

  95. ๊ฐ•์ œ๋กœ ์—…๋ฐ์ดํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์€?

    ๋งค์šฐ ๋“œ๋ฌธ ๊ฒฝ์šฐ์ง€๋งŒ, ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์Œ์—๋„ ์žฌ ๋ Œ๋”๋ง์„ ์œ„ํ•ด ๊ฐ•์ œ๋กœ ์—…๋ฐ์ดํŠธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ vm.$forceUpdate() API ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    Note: ๋ชจ๋“  ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—๋Š” ์˜ํ–ฅ์ด ๋ฏธ์น˜์ง€ ์•Š์œผ๋ฉฐ, ์Šฌ๋กฏ ๊ทธ ์ž์ฒด๊ฐ€ ์‚ฝ์ž…๋œ ์Šฌ๋กฏ ์ž์ฒด ๋ฐ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—๋งŒ ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค.

  96. ํ…œํ”Œ๋ฆฟ์—์„œ once ์ง€์‹œ์ž๋ฅผ ์“ฐ๋Š” ์ด์œ ๋Š”?

    ๋งŽ์€ ์–‘์˜ ์ •์  ์ปจํ…์ธ ๋ฅผ ๋ Œ๋”๋ง ํ•  ๋•Œ, ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์œ„ํ•ด ์—˜๋ฆฌ๋จผํŠธ ๋ฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•œ๋ฒˆ๋งŒ ๋ Œ๋”๋งํ•˜๋Š” ์šฉ๋„๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

    Vue.component('legal-terms', {
      template: `
        <div v-once>
          <h1>Legal Terms</h1>
          ... a lot of static content goes here...
        </div>
      `
    })

    Note: ์ •์  ์ปจํ…์ธ ๊ฐ€ ๋งŽ์•„์„œ ๋Š๋ ค์ง€๋Š” ์ผ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ํ•œ, ๊ณผ๋‹คํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

  97. ๋ฃจํŠธ Vue ์ธ์Šคํ„ด์Šค์— ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    ๋ฃจํŠธ Vue ์ธ์Šคํ„ด์Šค(new Vue())๋Š” $root ์†์„ฑ์„ ์ด์šฉํ•ด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    // The root Vue instance
    new Vue({
      data: {
        age: 26
      },
      computed: {
        fullName: function () { /* ... */ }
      },
      methods: {
        interest: function () { /* ... */ }
      }
    })

    ๋ฃจํŠธ ์ธ์Šคํ„ด์Šค์˜ ๋ฐ์ดํ„ฐ์™€ ๋ฉ”์†Œ๋“œ๋“ค์„ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    // Get root data
    this.$root.age
    
    // Set root data
    this.$root.age = 29
    
    // Access root computed properties
    this.$root.fullName
    
    // Call root methods
    this.$root.interest()

    ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ์šฉ๋„๋ผ๋ฉด Vuex๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋‚ซ์Šต๋‹ˆ๋‹ค.

  98. Vue๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ์—…๋“ค์€?

    ์•„๋ž˜๋Š” Vue๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ์œ ๋ช… ๊ธฐ์—…๋“ค์ž…๋‹ˆ๋‹ค.

    1. Facebook
    2. Netflix
    3. Adobe
    4. Xiaomi
    5. Alibaba
    6. WizzAir
    7. EuroNews
    8. Laracasts
    9. GitLab
    10. Laracasts
  99. renderError ๋ฉ”์†Œ๋“œ์˜ ๋ชฉ์ ์€?

    ๊ธฐ๋ณธ render ํ•จ์ˆ˜๊ฐ€ ๋ Œ๋”๋ง ๋„์ค‘ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ๋Œ€์ฒด๋˜๋Š” ๋ Œ๋”๋ง ๊ฒฐ๊ณผ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. renderError์˜ ๋‘ ๋ฒˆ์งธ ์ „๋‹ฌ์ธ์ž๋กœ ์—๋Ÿฌ๊ฐ€ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

    new Vue({
      render (h) {
        throw new Error('An error')
      },
      renderError (h, err) {
        return h('div', { style: { color: 'red' }}, err.stack)
      }
    }).$mount('#app')
  100. ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ง์ ‘ ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋“ค์„ $children ๋ฐฐ์—ด๋กœ ์ฐธ์กฐํ•˜๋ฉฐ, ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ $parent ์†์„ฑ์œผ๋กœ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.

  101. vuex๋ž€?

    Vuex๋Š” Vue.js ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ„ํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ํŒจํ„ด + ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(Flux์—์„œ ์˜๊ฐ์„ ๋ฐ›์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์•„ํ‚คํ…์ฒ˜)์ž…๋‹ˆ๋‹ค. ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ๋ฐฉ์‹์œผ๋กœ๋งŒ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋„๋ก ๋ณด์žฅํ•˜๋Š” ๊ทœ์น™์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋ฅผ ์œ„ํ•œ ์ค‘์•™ ์ง‘์ค‘์‹ ์ €์žฅ์†Œ์ž…๋‹ˆ๋‹ค.

  102. ์ƒํƒœ ๊ด€๋ฆฌ ํŒจํ„ด์˜ ์ฃผ์š” ๊ตฌ์„ฑ ์š”์†Œ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

    ์ƒํƒœ ๊ด€๋ฆฌ์˜ ์ฃผ์š” ๊ตฌ์„ฑ์š”์†Œ๋Š” ์ƒํƒœ ๋ฐ ๋ทฐ, ์•ก์…˜์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ตฌ์„ฑ์š”์†Œ์— ๋”ฐ๋ฅธ ํŒจํ„ด์„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ƒํƒœ ๊ด€๋ฆฌ ํŒจํ„ด์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์— ์ž์„ธํ•œ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์ž์„ธํžˆ ์„ค๋ช…๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

    1. ์ƒํƒœ๋Š” ์•ฑ์„ ๊ตฌ๋™์‹œํ‚ค๋Š” ์›์ฒœ์ž…๋‹ˆ๋‹ค.
    2. ๋ทฐ๋Š” ๋‹จ์ง€ ์ƒํƒœ์˜ ์„ ์–ธ์  ๋งคํ•‘์ž…๋‹ˆ๋‹ค.
    3. ์•ก์…˜์€ ๋ทฐ์—์„œ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์— ๋ฐ˜์‘ํ•˜์—ฌ ์ƒํƒœ๊ฐ€ ๋ณ€ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์œ„์˜ 3๊ฐ€์ง€ ๊ตฌ์„ฑ์š”์†Œ์™€ ํ•จ๊ป˜ ์ƒํƒœ ๊ด€๋ฆฌ ํŒจํ„ด์„ ๋”ฐ๋ฅด๋Š” ์นด์šดํ„ฐ ์˜ˆ๋ฅผ ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
    new Vue({
      // state
      data () {
        return {
          count: 0
        }
      },
      // view
      template: `
        <div>{{ count }}</div>
      `,
      // actions
      methods: {
        increment () {
          this.count++
        }
      }
    })
  103. Vuex์—์„œ ๋‹จ๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ํ๋ฆ„ ๋ชจ๋ธ์„ ์–ด๋–ป๊ฒŒ ํ‘œํ˜„ํ•ฉ๋‹ˆ๊นŒ?

    Vue.js๋Š” props ์†์„ฑ์„ ํ†ตํ•ด ๋‹จ๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ํ๋ฆ„ ๋ชจ๋ธ์„ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค. vuex์—์„œ ์ด์™€ ๋™์ผํ•œ ๊ฐœ๋…์€ ์•„๋ž˜์™€ ๊ฐ™์ด ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  104. vuejs loader๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

    Vue loader๋Š” Vue ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‹ฑ๊ธ€ ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ(SFC, SFCs)๋ผ๊ณ  ํ•˜๋Š” ํ˜•์‹์œผ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ์›นํŒฉ์šฉ ๋กœ๋”์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด HelloWorld ๋ผ๋Š” SFC๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    <template>
      <div class="greeting">{{ message }}</div>
    </template>
    
    <script>
    export default {
      data () {
        return {
          message: 'Hello world for vueloader!'
        }
      }
    }
    </script>
    
    <style>
    .greeting {
      color: blue;
    }
    </style>
  105. ์›นํŒฉ์—์„œ vue loader๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    Vue-Loader์˜ ์„ค์ •์€ ์›นํŒฉ ์„ค์ •์— Vue Loader์˜ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ๋กœ๋”์™€๋Š” ์•ฝ๊ฐ„ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. Vue ๋กœ๋” ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ์ •์˜๋œ ๋‹ค๋ฅธ ๊ทœ์น™(js ๋ฐ css ๊ทœ์น™)์„ ๋ณต์ œํ•˜์—ฌ .vue ํŒŒ์ผ์—์„œ ํ•ด๋‹น ์–ธ์–ด ๋ธ”๋ก(script ๋ฐ style)์— ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. Vue ๋กœ๋”์— ๋Œ€ํ•œ ์›นํŒฉ ๊ตฌ์„ฑ์˜ ๊ฐ„๋‹จํ•œ ์˜ˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    // webpack.config.js
    const VueLoaderPlugin = require('vue-loader/lib/plugin')
    
    module.exports = {
      mode: 'development',
      module: {
        rules: [
          {
            test: /\.vue$/,
            loader: 'vue-loader'
          },
          // this will apply to both plain `.js` files and `<script>` blocks in `.vue` files
          {
            test: /\.js$/,
            loader: 'babel-loader'
          },
          // this will apply to both plain `.css` files and `<style>` blocks in `.vue` files
          {
            test: /\.css$/,
            use: [
              'vue-style-loader',
              'css-loader'
            ]
          }
        ]
      },
      plugins: [
        // make sure to include the plugin for cloning and mapping them to respective language blocks
        new VueLoaderPlugin()
      ]
    }
  106. vue-loader์˜ Asset URL ํ•ธ๋“ค๋ง ๊ทœ์น™์€?

    1. ์ ˆ๋Œ€ ๊ฒฝ๋กœ(Absolute path): ๋งŒ์•ฝ URL ๊ฒฝ๋กœ๊ฐ€ /images/loader.png์™€ ๊ฐ™์€ ์ ˆ๋Œ€ ๊ฒฝ๋กœ๋ผ๋ฉด ๊ทธ๋Œ€๋กœ ๋ณด์กด๋ฉ๋‹ˆ๋‹ค.
    2. ์ƒ๋Œ€ ๊ฒฝ๋กœ(Relative path): ๋งŒ์•ฝ URL ๊ฒฝ๋กœ๊ฐ€ ./images/loader.png์™€ ๊ฐ™์€ ์ ˆ๋Œ€ ๊ฒฝ๋กœ๋ผ๋ฉด ์ƒ๋Œ€ ๋ชจ๋“ˆ ์š”์ฒญ(require(./images/loader.png))์œผ๋กœ ์ปดํŒŒ์ผ๋˜๊ณ  ํŒŒ์ผ ์‹œ์Šคํ…œ์˜ ํด๋” ๊ตฌ์กฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ด๊ฒฐ๋ฉ๋‹ˆ๋‹ค.
    3. ~๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒฝ๋กœ(URLs starts with ~ symbol): ๋งŒ์•ฝ URL ๊ฒฝ๋กœ๊ฐ€ ./some-node-package/loader.png์™€ ๊ฐ™์€ ~๋กœ ์‹œ์ž‘๋œ๋‹ค๋ฉด, ๋ชจ๋“ˆ ์š”์ฒญ์œผ๋กœ ์ปดํŒŒ์ผ๋ฉ๋‹ˆ๋‹ค.
    4. @๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒฝ๋กœ(URLs starts with @ symbol): ๋งŒ์•ฝ URL ๊ฒฝ๋กœ๊ฐ€ @๋กœ ์‹œ์ž‘๋œ๋‹ค๋ฉด, ๋ชจ๋“ˆ ์š”์ฒญ์œผ๋กœ ์ปดํŒŒ์ผ๋ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์›นํŒฉ config์— @์— ๋Œ€ํ•œ ๋ณ„์นญ์ด ์žˆ๋Š” ๊ฒฝ์šฐ์— ์œ ์šฉํ•˜๋ฉฐ, ๊ธฐ๋ณธ์ ์œผ๋กœ vue-cli๊ฐ€ ๋งŒ๋“  ๋ชจ๋“  ํ”„๋กœ์ ํŠธ์—์„œ /src๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.
  107. vue loader์—์„œ ์ „์ฒ˜๋ฆฌ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด?

    Vue-loader๋Š” ์ž‘์„ฑ๋œ ์–ธ์–ด ๋ธ”๋ก์˜ lang ์†์„ฑ์„ ์ด์šฉํ•ด ์ ์ ˆํ•œ ๋กœ๋”๋ฅผ ์ ์šฉํ•˜๊ณ  ์›นํŒฉ ์„ค์ •์— ์ ์šฉ๋œ ๊ทœ์น™์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. Vue-loader์—์„œ SASS, LESS, Stylus๋‚˜ PostCSS ๊ฐ™์€ ์ „์ฒ˜๋ฆฌ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  108. ๋ฒ”์œ„ CSS(Scoped CSS)๋ž€?

    ๋ฒ”์œ„๋ฅผ ๊ฐ€์ง€๋Š” CSS(Scoped CSS)๋Š” Vue์—์„œ ์‹ฑ๊ธ€ ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์— ์ž‘์„ฑ๋œ CSS๊ฐ€ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๋„๋ก ๊ทธ ์ ์šฉ ๋ฒ”์œ„๋ฅผ ์ œํ•œํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, <style> ํƒœ๊ทธ๊ฐ€ scoped ์†์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด, ํ•ด๋‹น CSS๋Š” ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์—์„œ๋งŒ ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค.

    <style scoped>
    .greeting {
      color: green;
    }
    </style>
    <template>
      <div class="greeting">Let's start Scoped CSS</div>
    </template>

    The above code will be converted to plain CSS,

     <style scoped>
     .greeting[data-v-f3f3eg9] {
       color: green;
     }
     </style>
    <template>
      <div class="greeting" data-v-f3f3eg9>Let's start Scoped CSS</div>
    </template>
  109. ๋ฒ”์œ„ CSS์™€ ์ „์—ญ CSS๋ฅผ ํ•จ๊ป˜ ์“ธ ์ˆ˜ ์žˆ์„๊นŒ?

    ๋ฒ”์œ„๊ฐ€ ์ง€์ •๋œ ์Šคํƒ€์ผ๊ณผ ๋ฒ”์œ„๊ฐ€ ์ง€์ •๋˜์ง€ ์•Š์€ ์Šคํƒ€์ผ์€ ๋™์ผํ•œ ์ปดํฌ๋„ŒํŠธ์— ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    <style>
    /* global styles */
    </style>
    
    <style scoped>
    /* local styles */
    </style>
  110. ๋ฒ”์œ„ CSS๊ฐ€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ฒŒ ํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

    ๋ฒ”์œ„๊ฐ€ ์ง€์ •๋œ CSS์—์„œ, ์ž์‹ ์ปดํฌ๋„ŒํŠธ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ฒŒ ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ >>> ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

    <style scoped>
    .class1 >>> .class2 { /* ... */ }
    </style>

    ์œ„์˜ CSS๋Š” ์•„๋ž˜๋กœ ์ปดํŒŒ์ผ๋ฉ๋‹ˆ๋‹ค.

    .class1[data-v-f3f3eg9] .class2 { /* ... */ }

    Note: SASS์—์„œ๋Š” >>> ์—ฐ์‚ฐ์ž๊ฐ€ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋•Œ๋Š” /deep/ ๋˜๋Š” ::v-deep ์„ ํƒ์ž๋ฅผ ๋Œ€์‹  ์ด์šฉํ•ฉ๋‹ˆ๋‹ค.

  111. Is parent styles leaked into child components in scoped css?

    The parent component's styles will not leak into child components. But a child component's root node will be affected by both the parent's scoped CSS and the child's scoped CSS. i.e, your child component's root element has a class that also exists in the parent component, the parent component's styles will leak to the child. Anyway this is by design so that the parent can style the child root element for layout purposes. For example, the background color property of parent component leaked into child component as below, //parent.vue

    <template>
      <div class="wrapper">
        <p>parent</p>
        <ChildMessageComponent/>
      </div>
    </template>
    
    <script>
    import ChildMessageComponent from "./components/child";
    
    export default {
      name: "App",
      components: {
        ChildMessageComponent
      }
    };
    </script>
    <style scoped>
    .wrapper {
      background: blue;
    }
    </style>

    //child.vue

    <template>
      <div class="wrapper">
        <p>child</p>
      </div>
    </template>
    
    <script>
    export default {
      name: "Hello, Scoped CSS",
    };
    </script>
    <style scoped>
    .wrapper {
      background: red;
    }
    </style>

    Now the background color of child wrapper is going to be blue instead red.

  112. How do you style dynamic generated content using scoped css?

    The scoped css style doesn't impact v-html directive's dynamically generated content. In this case, you can use deep selectors to solve this styling issue.

  113. Is CSS modules supported in Vuejs?

    Yes, vue-loader provides first-class integration with CSS Modules as an alternative for simulated scoped CSS.

  114. Can I use runtime builds for all templates?

    No, templates (or any Vue-specific HTML) are ONLY allowed in .vue files and render functions are required in other cases.

  115. How to use CSS modules in vuejs?

    Below are the steps to use css modules in VueJS,

    1. ** Enable CSS modules:** CSS Modules must be enabled by passing modules: true option to css-loader
    // webpack.config.js
    {
      module: {
        rules: [
          // ... other rules omitted
          {
            test: /\.css$/,
            use: [
              'vue-style-loader',
              {
                loader: 'css-loader',
                options: {
                  // enable CSS Modules
                  modules: true,
                  // customize generated class names
                  localIdentName: '[local]_[hash:base64:8]'
                }
              }
            ]
          }
        ]
      }
    }
    1. ** Add module attribute:** Add the module attribute to your <style>
    <style module>
    .customStyle {
      background: blue;
    }
    </style>
    1. ** Inject CSS modules:** You can inject CSS modules object with computed property $style
    <template>
      <div :class="$style.blue">
        Background color should be in blue
      </p>
    </template>

    It can work with object/array syntax of :class binding.

  116. Can I use CSS modules for preprocessors?

    Yes,You can use preprocessors with CSS Modules. For example, sass-loader can configured in webpack file for sass preprocessor.

    // webpack.config.js -> module.rules
    {
      test: /\.scss$/,
      use: [
        'vue-style-loader',
        {
          loader: 'css-loader',
          options: { modules: true }
        },
        'sass-loader'
      ]
    }
  117. Is it possible to use custom inject name for CSS modules?

    You can customize the name of the injected computed property by giving the module attribute a value. This will be helpful to avoid overwriting injected styled if you have more than one <style> tags in a single *.vue component. For example, you can use module attribute as below,

    <style module="a">
      /* identifiers injected as a */
    </style>
    
    <style module="b">
      /* identifiers injected as b */
    </style>
  118. What is hot reloading in vue loader?

    Hot reloading is not about reloading the page when you edit any .vue file. Instead, when you edit a *.vue file, all instances of that component will be swapped in without reloading the page. It improves the development experience when you are tweaking the templates or styling of your components.

  119. What is the default behavior of hot reloading?

    Hot Reload is always enabled except below situations:

    1. webpack target is node (SSR)
    2. webpack minifies the code
    3. process.env.NODE_ENV === 'production'
  120. How do you disable hot reloading explicitly?

    You can use hotReload: false option to disable the Hot Reload explicitly. It can be configured as below,

    module: {
      rules: [
        {
          test: /\.vue$/,
          loader: 'vue-loader',
          options: {
            hotReload: false // disables Hot Reload
          }
        }
      ]
    }
  121. How do you use hot reloading?

    The vue loader plugin internally uses hot reloading. If you are scaffolding project with vue-cli, hot reloading comes out of the box but if you are manually setting up the project then hot reloading is enabled by default with webpack-dev-server --hot command.

  122. What are state preservation rules in hot reloading?

    Below are the state preservation rules in hot reloading, 1.When editing the <template> of a component, instances of the edited component will re-render in place, preserving all current private state. 2.When editing the <script> part of a component, instances of the edited component will be destroyed and re-created in place. 3.When editing the <style> hot reload operates on its own via vue-style-loader without affecting application state.

  123. How to create functional components using vue loader?

    You can create functional components by adding functional attribute to template block,

    <template functional>
      <div>{{ props.msg }}</div>
    </template>
  124. How do you access global properties of functional components?

    If you need to access properties defined globally on Vue.prototype then you can access them on parent,

    <template functional>
      <div>{{ parent.$someProperty }}</div>
    </template>
  125. How do you perform testing in vuejs?

    You can perform testing in two ways,

    1. ** Using vue-cli:** It offers pre-configured unit testing and e2e testing setups
    2. ** Manual setup:** You can manually setting up unit tests for *.vue files using either mocha-webpack or jest
  126. How do you apply linting for css?

    The stylelint linter supports linting style parts of Vue single file components. You can run linter on particular vue file as below

    stylelint MyComponent.vue

    Other option is configuring stylelint-webpack-plugin in webpack. It can be configured as a dev dependency.

    // webpack.config.js
    const StyleLintPlugin = require('stylelint-webpack-plugin');
    module.exports = {
      // ... other options
      plugins: [
        new StyleLintPlugin({
          files: ['**/*.{vue,htm,html,css,sss,less,scss,sass}'],
        })
      ]
    }
  127. How do you use eslint plugin?

    The official eslint-plugin-vue supports linting both the template and script parts of Vue single file components. You can configure plugin in your ESLint config,

    // .eslintrc.js
    module.exports = {
      extends: [
        "plugin:vue/essential"
      ]
    }

    You can run linter on particular component as below,

    eslint --ext js,vue MyComponent.vue
  128. What is the purpose of eslint loader?

    You can use eslint-loader for *.vue files in order to automatically linted on save during development. It can be installed as npm module,

    npm install -D eslint eslint-loader

    After that you need to add it as pre-loader,

    // webpack.config.js
    module.exports = {
      // ... other options
      module: {
        rules: [
          {
            enforce: 'pre',
            test: /\.(js|vue)$/,
            loader: 'eslint-loader',
            exclude: /node_modules/
          }
        ]
      }
    }
  129. What is CSS extraction?

    CSS Extraction is used to extract all the processed CSS in all Vue components into a single CSS file. For webpack4, you need to install below npm command,

    npm install -D mini-css-extract-plugin

    You can configure this plugin in webpack as below,

    // webpack.config.js
    var MiniCssExtractPlugin = require('mini-css-extract-plugin')
    
    module.exports = {
      // other options...
      module: {
        rules: [
          // ... other rules omitted
          {
            test: /\.css$/,
            use: [
              process.env.NODE_ENV !== 'production'
                ? 'vue-style-loader'
                : MiniCssExtractPlugin.loader,
              'css-loader'
            ]
          }
        ]
      },
      plugins: [
        // ... Vue Loader plugin omitted
        new MiniCssExtractPlugin({
          filename: 'style.css'
        })
      ]
    }
  130. What are custom blocks?

    You can define custom language blocks inside *.vue files based on the lang attribute of the block, the block's tag name, and the rules in your webpack config. You can also use resourceQuery to match a rule against a custom block with no lang. For example, to match against custom blocks.

    {
      module: {
        rules: [
          {
            resourceQuery: /blockType=message/,
            loader: 'loader-to-use'
          }
        ]
      }
    }
  131. What are the features of stylelint?

    Below are the list of major stylelint features

    1. It has more than 160 built-in rules to catch errors, apply limits and enforce stylistic conventions
    2. Understands latest CSS syntax including custom properties and level 4 selectors
    3. It extracts embedded styles from HTML, markdown and CSS-in-JS object & template literals
    4. Parses CSS-like syntaxes like SCSS, Sass, Less and SugarSS
    5. Supports Plugins for reusing community plugins and creating own plugins
  132. What are the principles for vuex application structure?

    Vuex enforces below rules to structure any application.

    1. Application-level state is centralized in the store.
    2. The only way to mutate the state is by committing mutations, which are synchronous transactions.
    3. Asynchronous logic should be encapsulated in, and can be composed with actions. The project structure for any non-trivial application would be as below,
  133. Is Vuex supports hot reloading?

    Yes, Vuex supports hot-reloading for mutations, modules, actions and getters during development. You need to use either webpack's hot module replacement API or browserify's hot module replacement plugin.

  134. What is the purpose of hotUpdate API of vuex store?

    The store.hotUpdate() API method is used for mutations and modules. For example, you need to configure vuex store as below,

    // store.js
    import Vue from 'vue'
    import Vuex from 'vuex'
    import mutations from './mutations'
    import myModule from './modules/myModule'
    
    Vue.use(Vuex)
    
    const state = { message: "Welcome to hot reloading" }
    
    const store = new Vuex.Store({
      state,
      mutations,
      modules: {
        moduleA: myModule
      }
    })
    
    if (module.hot) {
      // accept actions and mutations as hot modules
      module.hot.accept(['./mutations', './modules/newMyModule'], () => {
        // Get the updated modules
        const newMutations = require('./mutations').default
        const newMyModule = require('./modules/myModule').default
        //swap in the new modules and mutations
        store.hotUpdate({
          mutations: newMutations,
          modules: {
            moduleA: newMyModule
          }
        })
      })
    }
  135. How do you test mutations?

    Since mutations are just functions that completely rely on their arguments it will be easier to test. You need to keep mutations inside your store.js file and should also export the mutations as a named export apart from default export. Let's take an example of increment mutations,

    // mutations.js
    export const mutations = {
      increment: state => state.counter++
    }

    And test them using mocha and chai as below,

    // mutations.spec.js
    import { expect } from 'chai'
    import { mutations } from './store'
    
    // destructure assign `mutations`
    const { increment } = mutations
    
    describe('mutations', () => {
      it('INCREMENT', () => {
        // mock state
        const state = { counter: 10 }
        // apply mutation
        increment(state)
        // assert result
        expect(state.counter).to.equal(11)
      })
    })
  136. How do you test your getters?

    It is easier to test getters similar to mutations. It is recommended to test these getters if they have complicated computation. Let's take a simple todo filter as a getter

    // getters.js
    export const getters = {
      filterTodos (state, status) {
        return state.todos.filter(todo => {
          return todo.status === status
        })
      }
    }

    And the test case for above getter as follows,

    // getters.spec.js
    import { expect } from 'chai'
    import { getters } from './getters'
    
    describe('getters', () => {
      it('filteredTodos', () => {
        // mock state
        const state = {
          todos: [
            { id: 1, title: 'design', status: 'Completed' },
            { id: 2, title: 'testing', status: 'InProgress' },
            { id: 3, title: 'development', status: 'Completed' }
          ]
        }
        // mock getter
        const filterStatus = 'Completed'
    
        // get the result from the getter
        const result = getters.filterTodos(state, filterStatus)
    
        // assert the result
        expect(result).to.deep.equal([
          { id: 1, title: 'design', status: 'Completed' },
          { id: 2, title: 'development', status: 'Completed' }
        ])
      })
    })
  137. What is the procedure to run tests in node?

    By proper mocking, you can bundle tests with webpack and run them on node without having depenceny on Browser API. It involves 2 steps,

    1. Create webpack config: Create webpack config with proper .babelrc
    // webpack.config.js
    module.exports = {
      entry: './test.js',
      output: {
        path: __dirname,
        filename: 'test-bundle.js'
      },
      module: {
        loaders: [
          {
            test: /\.js$/,
            loader: 'babel-loader',
            exclude: /node_modules/
          }
        ]
      }
    }
    
    1. ** Run testcases:** First you need to bundle and then run them using mocha as below,
    webpack
    mocha test-bundle.js
  138. What is the procedure to run tests in browser?

    Below are the steps to run tests in real browser,

    1. Install mocha-loader.
    2. Configure webpack config entry point to 'mocha-loader!babel-loader!./test.js'.
    3. Start webpack-dev-server using the config.
    4. Go to localhost:8080/webpack-dev-server/test-bundle to see the test result
  139. What is the purpose of strict mode in vuex?

    In strict mode, whenever Vuex state is mutated outside of mutation handlers, an error will be thrown. It make sure that all state mutations can be explicitly tracked by debugging tools. You can just enable this by passing strict: true while creating the vuex store.

    const store = new Vuex.Store({
      // ...
      strict: true
    })
  140. Can I use strict mode in production environment?

    No, it is not recommended to use strict mode in production environment. Strict mode runs a synchronous deep watcher on the state tree for detecting inappropriate mutations and it can be quite expensive when you perform large amount of mutations. i.e, It can impact performance if you enable in production mode. Hence it should be handled through build tools,

    const store = new Vuex.Store({
      // ...
      strict: process.env.NODE_ENV !== 'production'
    })
  141. What is vuex plugin?

    The vuex plugin is an option hat exposes hooks for each mutation. It is a normal function that receives the store as the only argument. You can create your own plugin or use built-in plugins. The plugin skeleton would be as below,

    const myPlugin = store => {
      // called when the store is initialized
      store.subscribe((mutation, state) => {
        // called after every mutation.
        // The mutation comes in the format of `{ type, payload }`.
      })
    }

    After that plugin can be configured for plugins options as below,

    const store = new Vuex.Store({
      // ...
      plugins: [myPlugin]
    })
  142. How do you mutate state in plugins?

    Similar to components you can't mutate state directly but they can trigger changes by by committing mutations. This way a plugin can be used to sync a data source to the store. For example, createWebSocketPlugin plugin is used to sync a websocket data source to the store.

    export default function createWebSocketPlugin (socket) {
      return store => {
        socket.on('data', data => {
          store.commit('receiveData', data)
        })
        store.subscribe(mutation => {
          if (mutation.type === 'UPDATE_DATA') {
            socket.emit('update', mutation.payload)
          }
        })
      }
    }

    And then configure plugin in vuex store as below

    const plugin = createWebSocketPlugin(socket)
    
    const store = new Vuex.Store({
      state,
      mutations,
      plugins: [plugin]
    })
  143. What is vuex store?

    A Vuex "store" is basically a container that holds your application state. The store creation is pretty straightforward. Below are the list of instructions to use vuex in an increment application,

    1. Configure vuex in vuejs ecosystem
    import Vuex from "vuex";
    Vue.use(Vuex)
    1. Provide an initial state object and some mutations
    // Make sure to call Vue.use(Vuex) first if using a module system
    
    const store = new Vuex.Store({
      state: {
        count: 0
      },
      mutations: {
        increment (state) {
          state.count++
        }
      }
    })
    1. Trigger state change with commit and access state variables,
    store.commit('increment')
    
    console.log(store.state.count) // -> 1
  144. What are the differences of vuex store and plain global object?

    Below are the two major differences between vuex store and plain global object

    1. Vuex stores are reactive: If the store's state changes then vue components will reactively and efficiently get updated
    2. Cannot directly mutate the store's state: The store's state is changed by explicitly committing mutations to ensure that every state change leaves a track-able record for tooling purpose
  145. What is the reason not to update the state directly?

    We want to explicitly track application state in order to implement tools that can log every mutation, take state snapshots, or even perform time travel debugging. So we need to commit a mutation instead of changing store's state directly.

  146. What is Single state tree?

    Vuex's single state tree is single object contains all your application level state and serves as the "single source of truth". It does not conflict with modularity when you split state and mutations into sub modules.

  147. How do you install vuex?

    You can install vuex using npm or yarn as below,

    npm install vuex --save
    (or)
    yarn add vuex

    In a module system, you must explicitly install Vuex via Vue.use()

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)

    (OR) You can also install it using CDN links such as unpkg.cpm which provides NPM-based CDN links. Just include vuex after Vue and it will install itself automatically.

    <script src="https://unpkg.com/vue.js"></script>
    <script src="https://unpkg.com/vuex.js"></script>

    Note: You can use a specific version/tag via URLs like https://unpkg.com/vuex@2.0.0. If you don't mention any version then it will point to latest version.

  148. Do I need promise for vuex?

    Yes, Vuex requires Promise. If your supporting browsers do not implement Promise (e.g. IE), you can use a polyfill library, such as es6-promise using npm or yarn.

    npm install es6-promise --save # NPM
    yarn add es6-promise # Yarn

    After that import into anywhere in your application,

    import 'es6-promise/auto'
  149. How do you display store state in vue components?

    Since Vuex stores are reactive, you can retrieve" state from store by simply returning store's state from within a computed property. i.e, Whenever store state changes, it will cause the computed property to re-evaluate, and trigger associated DOM updates. Let's take a hello word component which display store's state in the template,

    // let's create a hello world component
    const Greeting = {
      template: `<div>{{ greet }}</div>`,
      computed: {
        greet () {
          return store.state.msg
        }
      }
    }
  150. How do you inject store into child components?

    Vuex provides a mechanism to "inject" the store into all child components from the root component with the store option. It will be enabled by vue.use(vuex). For example, let's inject into our app component as below,

    const app = new Vue({
      el: '#app',
      // provide the store using the "store" option.
      // this will inject the store instance to all child components.
      store,
      components: { Greeting },
      template: `
        <div class="app">
          <greeting></greeting>
        </div>
      `
    })

    Now the store will be injected into all child components of the root and will be available on them as this.$store

     // let's create a hello world component
         const Greeting = {
           template: `<div>{{ greet }}</div>`,
           computed: {
             greet () {
               return this.$store.state.msg
             }
           }
         }
  151. What is mapState helper?

    In Vuex application, creating a computed property every time whenever we want to access the store's state property or getter is going to be repetitive and verbose, especially if a component needs more than one state property. In this case, we can make use of the mapState helper of vuex which generates computed getter functions for us. Let's take an increment example to demonstrate mapState helper,

    // in full builds helpers are exposed as Vuex.mapState
    import { mapState } from 'vuex'
    
    export default {
      // ...
      computed: mapState({
        // arrow functions can make the code very succinct!
        username: state => state.username,
    
        // passing the string value 'username' is same as `state => state.username`
        usernameAlias: 'username',
    
        // to access local state with `this`, a normal function must be used
         greeting (state) {
          return this.localTitle + state.username
        }
      })
    }

    We can also pass a string array to mapState when the name of a mapped computed property is the same as a state sub tree name

    computed: mapState([
      // map this.username to store.state.username
      'username'
    ])
  152. How do you combine local computed properties with mapState helper?

    You can use object spread operator syntax in order to combine mapState helper(which returns an object) with other local computed properties. This way it simplify merging techniques using utilities.

    computed: {
      localComputed () { /* ... */ },
      // mix this into the outer object with the object spread operator
      ...mapState({
        // ...
      })
    }
  153. Do you need to replace entire local state with vuex?

    No, if a piece of state strictly belongs to a single component, it could be just fine leaving it as local state. i.e, Eventhough vuex used in the application, it doesn't mean that you need to keep all the local state in vuex store. Other the code becomes more verbose and indirect although it makes your state mutations more explicit and debuggable.

  154. What are vuex getters??

    Vuex getters acts as computed properties for stores to compute derived state based on store state. Similar to computed properties, a getter's result is cached based on its dependencies, and will only re-evaluate when some of its dependencies have changed. Let's take a todo example which as completedTodos getter to find all completed todos,

    const store = new Vuex.Store({
      state: {
        todos: [
          { id: 1, text: 'Vue course', completed: true },
          { id: 2, text: 'Vuex course', completed: false },
          { id: 2, text: 'Vue Router course', completed: true }
        ]
      },
      getters: {
        completedTodos: state => {
          return state.todos.filter(todo => todo.completed)
        }
      }
    })

    **Note:**Getters receive state as first argument.

  155. What is a property style access?

    You can access values of store's getter object(store.getters) as properties. This is known as property style access. For example, you can access todo's status as a property,

    store.getters.todosStatus

    The getters can be passed as 2nd argument for other getters. For example, you can derive completed todo's count based on their status as below,

    getters: {
      completedTodosCount: (state, getters) => {
        return getters.todosStatus === 'completed'
      }
    }

    Note: The getters accessed as properties are cached as part of Vue's reactivity system.

  156. What is a method style access?

    You can access store's state in a method style by passing arguments. For example, you can pass user id to find user profile information as below,

    getters: {
      getUserProfileById: (state) => (id) => {
        return state.users.find(user => user.id === id)
      }
    }

    After that you can access it as a method call,

    store.getters.getUserProfileById(111); {id: '111', name: 'John', age: 33}
  157. What is mapGetter helper??

    The mapGetters is a helper that simply maps store getters to local computed properties. For example, the usage of getters for todo app would be as below,

    import { mapGetters } from 'vuex'
    
    export default {
      computed: {
        // mix the getters into computed with object spread operator
        ...mapGetters([
          'completedTodos',
          'todosCount',
          // ...
        ])
      }
    }
  158. What are mutations?

    Vuex mutations are similar to any events with a string type and a handler. The handler function is where we perform actual state modifications, and it will receive the state as the first argument. For example, the counter example with increment mutation would be as below,

    const store = new Vuex.Store({
      state: {
        count: 0
      },
      mutations: {
        increment (state) {
          // mutate state
          state.count++
        }
      }
    })

    You can't directly invoke mutation instead you need to call store.commit with its type. The above mutation would be triggered as folows

    store.commit('increment')
  159. How do you commit with payload?

    You can also pass payload for the mutation as an additional argument to store.commit. For example, the counter mutation with payload object would be as below,

    mutations: {
      increment (state, payload) {
        state.count += payload.increment
      }
    }

    And then you can trigger increment commit

    store.commit('increment', {
      increment: 20
    })

    Note: You can also pass primitives as payload.

  160. What is object style commit?

    You can also commit a mutation is by directly using an object that has a type property.

    store.commit({
      type: 'increment',
      value: 20
    })

    Now the entire object will be passed as the payload to mutation handlers(i.e, without any changes to handler signature).

    mutations: {
      increment (state, payload) {
        state.count += payload.value
      }
    }
  161. What are the caveats with vuex mutations?

    Since a Vuex store's state is made reactive by Vue, the same reactivity caveats of vue will apply to vuex mutations. These are the rules should be followed for vuex mutations,

    1. It is recommended to initialize store's initial state with all desired fields upfront
    2. Add new properties to state Object either by set method or object spread syntax
    Vue.set(stateObject, 'newProperty', 'John')

    (OR)

    state.stateObject = { ...state.stateObject, newProperty: 'John' }
  162. Why mutations should be synchronous?

    You need to remember that mutation handler functions must be synchronous. This is why because any state mutation performed in the callback is essentially un-trackable. It is going to be problematic when the devtool will need to capture a "before" and "after" snapshots of the state during the mutations.

    mutations: {
      someMutation (state) {
        api.callAsyncMethod(() => {
          state.count++
        })
      }
    }
  163. How do you perform mutations in components?

    You can commit mutations in components with either this.$store.commit('mutation name') or mapMutations helper to map component methods to store.commit calls. For example, the usage of mapMutations helper on counter example would be as below,

    import { mapMutations } from 'vuex'
    
    export default {
      methods: {
        ...mapMutations([
          'increment', // map `this.increment()` to `this.$store.commit('increment')`
    
          // `mapMutations` also supports payloads:
          'incrementBy' // map `this.incrementBy(amount)` to `this.$store.commit('incrementBy', amount)`
        ]),
        ...mapMutations({
          add: 'increment' // map `this.add()` to `this.$store.commit('increment')`
        })
      }
    }
  164. Is it mandatory to use constants for mutation types?

    No, it is not mandatory. But you might observed that State management implementations such Flux and Redux use constants for mutation types. This convention is just a preference and useful to take advantage of tooling like linters, and putting all constants in a single file allows your collaborators to get an at-a-glance view of what mutations are possible in the entire application. For example, the mutations can be declared as below,

    // mutation-types.js
    export const SOME_MUTATION = 'SOME_MUTATION'

    And you can configure them in store as follows,

    // store.js
    import Vuex from 'vuex'
    import { SOME_MUTATION } from './mutation-types'
    
    const store = new Vuex.Store({
      state: { ... },
      mutations: {
        // ES2015 computed property name feature to use a constant as the function name
        [SOME_MUTATION] (state) {
          // mutate state
        }
      }
    })
  165. How do you perform asynchronous operations?

    In Vuex, mutations are synchronous transactions. But if you want to handle asynchronous operations then you should use actions.

  166. What are differences between mutations and actions?

    Actions are similar to mutations, but there are two main differences,

    1. Mutations perform mutations on the state, actions commit mutations.
    2. Actions can contain arbitrary asynchronous operations unlike mutations.

About

VueJS interview questions in Korean language