Intro to Vue.js

What, Why, and How

1. What is Vue.js?

a progressive framework for building user interfaces

1. Front End

2. SPA (Single Page Application)

  • ๋‹จ์ผ ํŽ˜์ด์ง€๋กœ ๊ตฌ์„ฑ๋œ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜

  • ํ™”๋ฉด์ด๋™ ์‹œ์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์„œ๋ฒ„์‚ฌ์ด๋“œ์—์„œ HTML์œผ๋กœ ์ „๋‹ฌ๋ฐ›์ง€ ์•Š๊ณ (์„œ๋ฒ„์‚ฌ์ด๋“œ ๋ Œ๋”๋ง X), ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋งŒ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ JSON์œผ๋กœ ์ „๋‹ฌ ๋ฐ›์•„ ๋™์ ์œผ๋กœ ๋ Œ๋”๋ง

    • client side rendering!

  • ๋ชจ๋“  HTML์„ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ฐ–๊ณ  ์žˆ๊ณ  ์„œ๋ฒ„์‚ฌ์ด๋“œ์—๋Š” ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๊ณ  JSON์œผ๋กœ ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ์กด์˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋น„ํ•ด ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•˜๋Š” ์†๋„๊ฐ€ ๋น ๋ฅด๋‹ค

  • ์žฅ์ 

    • ํ•˜๋‚˜ํ•˜๋‚˜ ํ™”๋ฉด ์ „์ฒด๋ฅผ ๋ Œ๋”๋งํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ํ™”๋ฉด์ด๋™์ด ๋น ๋ฅด๋‹ค.

    • ํ™”๋ฉด์— ํ•„์š”ํ•œ ๋ถ€๋ถ„์˜ ๋ฐ์ดํ„ฐ๋งŒ ๋ฐ›์•„์„œ ๋ Œ๋”๋ง ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฒ˜๋ฆฌ๊ณผ์ •์ด ํšจ์œจ์ ์ด๋‹ค.

    • ์œ ์ €์— ์ž…์žฅํ•ด์„œ ์‚ฌ์šฉํ•˜๊ธฐ ํŽธ๋ฆฌํ•˜๋‹ค.

  • ๋‹จ์ 

    • ์ฒ˜์Œ ํ™”๋ฉด์„ ๋กœ๋”ฉํ•  ๋•Œ, ๋ชจ๋“  ํ™”๋ฉด์ด ๋ฏธ๋ฆฌ ์ค€๋น„๋˜์–ด ์žˆ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋กœ๋”ฉ์— ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฐ๋‹ค.

    • ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ ๋ณด๋‹ค ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋ฉฐ ๋ณต์žกํ•˜๋‹ค.

      ์ฐธ๊ณ : https://velog.io/@josworks27/SPA-%EA%B0%9C%EB%85%90

3. Client Side Rendering

image-20200525101243092

4. MVVN (Model View ViewModel) Pattern

image-20200525101419720
  • ๊ตฌ์กฐ

    • Model

      • ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋ฐ์ดํ„ฐ์™€ ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ถ€๋ถ„

    • View

      • ์‚ฌ์šฉ์ž์—์„œ ๋ณด์—ฌ์ง€๋Š” UI ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

    • View Model

      • View๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“  View๋ฅผ ์œ„ํ•œ Model

      • View๋ฅผ ๋‚˜ํƒ€๋‚ด ์ฃผ๊ธฐ ์œ„ํ•œ Model์ด์ž View๋ฅผ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” ๋ถ€๋ถ„

  • ๋™์ž‘ ์ˆœ์„œ

    • ์‚ฌ์šฉ์ž์˜ Action๋“ค์€ View๋ฅผ ํ†ตํ•ด ๋“ค์–ด์˜ค๊ฒŒ ๋จ

    • View์— Action์ด ๋“ค์–ด์˜ค๋ฉด, Command ํŒจํ„ด์œผ๋กœ View Model์— Action์„ ์ „๋‹ฌ

    • View Model์€ Model์—๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญ

    • Model์€ View Model์—๊ฒŒ ์š”์ฒญ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ์‘๋‹ต

    • View Model์€ ์‘๋‹ต ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€๊ณตํ•˜์—ฌ ์ €์žฅ

    • View๋Š” View Model๊ณผ Data Bindingํ•˜์—ฌ ํ™”๋ฉด์„ ๋‚˜ํƒ€๋ƒ„

  • ์žฅ์ 

    • MVVM ํŒจํ„ด์€ View์™€ Model ์‚ฌ์ด์˜ ์˜์กด์„ฑ์ด ์—†๋‹ค

    • ๋˜ํ•œ Command ํŒจํ„ด๊ณผ Data Binding์„ ์‚ฌ์šฉํ•˜์—ฌ View์™€ View Model ์‚ฌ์ด์˜ ์˜์กด์„ฑ ๋˜ํ•œ ์—†์•ค ๋””์ž์ธํŒจํ„ด

    • ๊ฐ๊ฐ์˜ ๋ถ€๋ถ„์€ ๋…๋ฆฝ์ ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋“ˆํ™” ํ•˜์—ฌ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์Œ

      ์ถœ์ฒ˜: https://beomy.tistory.com/43 [beomy]

  • Vue.js ๋Š” MVVM ํŒจํ„ด์˜ ViewModel ๋ ˆ์ด์–ด์— ํ•ด๋‹นํ•˜๋Š” View ๋‹จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค

5. ๋ฐ˜์‘ํ˜• (Reactive)

Vue vs React

๊ณตํ†ต์ 

  • ๊ฐ€์ƒ DOM์„ ํ™œ์šฉ

  • ๋ฐ˜์‘์ ์ด๊ณ  ์กฐํ•ฉ ๊ฐ€๋Šฅํ•œ component ์ œ๊ณต

  • core library์—๋งŒ ์ง‘์ค‘ํ•˜๊ณ  ์žˆ๊ณ  routing ๋ฐ ์ „์—ญ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” companion library๊ฐ€ ์žˆ์Œ

+

Vue.js ์™€ ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ์™€์˜ ๋น„๊ต

https://kr.vuejs.org/v2/guide/comparison.html

2. Why Vue.js?

  1. ๋ฐฐ์šฐ๊ธฐ ์‰ฝ๋‹ค!

  2. $ (์ ˆ์•ฝ)

    • Client Side Rendering

  3. UX ํ–ฅ์ƒ

    • ๋น„๋™๊ธฐ / SPA

  4. ํ”„๋ ˆ์ž„์›Œํฌ (ํ”„๋ Œ์ฒด์ด์ฆˆ)์˜ ์žฅ์  (DX ํ–ฅ์ƒ - ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜ ํ–ฅ์ƒ)

    • No etc, ์„ ํƒ๊ณผ ์ง‘์ค‘

    • ์œ ์ง€/๋ณด์ˆ˜ ์šฉ์ด

    • Community์™€ library

3. How?

Setups

  • VS Code

    • Vetur ์„ค์น˜

  • Chrome Web Store

    • Vue.js devtools

      • ๋ฐ‘์˜ ๋‘ ๊ฐ€์ง€ ์„ ํƒํ•˜๊ธฐ

      image-20200525103628912
  • CDN

    • (์ง€๊ธˆ์€) ์œ„์˜ ๊ฐœ๋ฐœ version ์‚ฌ์šฉํ•˜๊ธฐ


<br>

<br>

### Docs

https://kr.vuejs.org/v2/guide/index.html

- ์ •๋ง ์ž˜ ์ •๋ฆฌ๋˜์–ด ์žˆ๋‹ค! ๋”ฐ๋ผํ•ด๋ณด๋ฉฐ ์ตํžˆ๊ธฐ!

<br>

<br>

## 4. Getting started with Vue.js 

<br>

### 4-0. `el` attribute

- Vue instance ์•ˆ์— `el` ์†์„ฑ์„ ํ†ตํ•ด Vue instance๊ฐ€ ๊ทธ๋ ค์งˆ ์ง€์ ์„ ์ง€์ •

ex)

> 00_el.html

```html
<body>
  <div id="app">

  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
      // el์€ Vue instance์˜ ์†์„ฑ์ด๋‹ค
      const app = new Vue({
          el: '#app', // ์–ด๋–ค ์š”์†Œ์— mount ํ•  ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๊ตฌ๊ฐ„
      })
      console.log(app)
      console.log(app.$el)
  </script>
</body>

4-1. data attribute

  • ํ™”๋ฉด์— ๋ณด์—ฌ์งˆ ๋ฐ์ดํ„ฐ๋ฅผ ์ •์˜

ex)

01_data.html

<body>
    <div id="app">
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            // Data๋ฅผ ์„ ์–ธํ•˜๋Š” ๋ฐฉ๋ฒ•
            data: { // MVVM ์˜ Model์„ ๋‹ด๋‹นํ•˜๋Š” ๊ตฌ๊ฐ„
                message:'Hello Vue!'
            }
        })
        console.log(app.message) 
    </script>
</body>

4-2. Interpolation

ex)

02_interpolation.html

<body>
    {{ message }}
    <div id="app">
        {{ message }}
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data: {
                message:'Hello Vue!'
            }
        })
        console.log(app.message) 
    </script>
</body>

4-3. v-text

  • Vannila JS์˜ DomElement.innertext์™€ ๊ฐ™์Œ

  • v- ์ ‘๋‘์‚ฌ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ๋“ค์„ ๋ชจ๋‘ directive(๋ช…๋ น)๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค

ex)

03_v-text.html

<div id="app">
        <p v-text="message"></p>
        <p> {{message}}</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data: {
                message:'์™„์ „ํžˆ ๊ฐ™์•„์š”!'
            }
        })
        console.log(app.message) 
    </script>
</body>

4-4. v-if

  • if ํ‰๊ฐ€์—์„œ false์ด๋ฉด ํ™”๋ฉด์— ๋‚˜์˜ค์ง€ ์•Š๋Š”๋‹ค

ex)

04_v-if.html

<body>
    <div id="app">
        <p v-if="bool1">
            true
        </p>
        <p v-if="bool2">
            false
        </p>

        <p v-if="str1">
            'Yes'
        </p>
        <p v-if="str2">
            ''
        </p>

        <p v-if="num1">
            1
        </p>
        <p v-if="num2">
            0
        </p>

        <!-- JavaScript ๋Š” empty array๋„ true-->
        <p v-if="arr">
            [] => js๋Š” ๋นˆ ๋ฐฐ์—ด์ด true ํ‰๊ฐ€
        </p>
        <p v-if="arr.length">
            [].length๋ฅผ ํ†ตํ•ด 0์ธ์ง€๋กœ ํ™•์ธ
        </p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data: {
                bool1: true,
                bool2: false,
                str1: 'Yes',
                str2: '',
                num1: 1,
                num2: 0,
                arr: [],
            }
        })
        console.log(app.message) 
    </script>
</body>

4-5. v-if, v-else-if, v-else

ex)

05_v-if-elseif-else.html

<body>
    <div id="app">
        <p v-if="username === 'master'">
            Hello Master
        </p>
        <p v-else>
            Hello User
        </p>

        <p v-if="number > 0">
            ์–‘์ˆ˜
        </p>
        <p v-else-if="number < 0">
            ์Œ์ˆ˜
        </p>
        <p v-else>
            0
        </p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data: {
             username: 'master',
             number: 0,
            }
        })
    </script>
</body>

4-6. v-for

ex)

06_v-for.html

<body>
    <div id="app">
        <ul>
            <li v-for="number in numbers">{{ number +1 }}</li>
        </ul>

        <ol>
            <li v-for="teacher in teachers"> {{ teacher.name }}</li>
        </ol>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data: { 
                numbers: [0,1,2,3,4,5],
                teachers: [
                    { name: 'neo'},
                    { name: 'tak'},
                ],
            }
        })
    </script>
</body>

4-7. v-bind

  • ํ‘œ์ค€ HTML ์†์„ฑ๊ณผ Vue Instance๋ฅผ ์—ฐ๋™ํ•  ๋•Œ ์‚ฌ์šฉ (+ a)

  • v-bind: ๋ฅผ ์ค„์—ฌ์„œ : ์œผ๋กœ ์“ธ ์ˆ˜ ์žˆ๋‹ค!

ex)

07_v-bind.html

<body>
    <div id="app">
        <a href=" {{ googleUrl }}">Bad Google link</a>
        <a v-bind:href="googleUrl">Good Google link</a>
        <a :href="naverUrl">Naver link</a>
        <img :src="randomImageUrl" v-bind:alt="altText">
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data: { 
                googleUrl: 'https://google.com',
                naverUrl: 'https://naver.com',
                randomImageUrl: 'https://picsum.photos/200',
                altText: 'random-image',
            }
        })
    </script>
</body>

4-8. methods attribute

ex)

08_methods.html

<body>
    <div id="app">
        {{ message }}
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data: { 
                message:'Hello Vue!'
            },
            methods: {
                alertWarning: function() {
                    alert('WARNING!')
                },
                // Syntatic sugar : ์œ„์™€ ์•„๋ž˜๋Š” ์™„์ „ํžˆ ๊ฐ™๋‹ค!
                alertMessage(){
                    alert(this.message)
                    // Vue ์„ธ์ƒ์˜ this -> JS์™€ ๋‹ค๋ฅด๊ฒŒ ์ ์šฉ๋จ
                    // : ๋‚ด๋ถ€์ ์œผ๋กœ proxy system์ด ์ ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ 
                },
                changeMessage(){
                    this.message = 'Changed message'
                }
            }
        })
    </script>

4-9 v-on

  • listener๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๊ฒƒ

  • v-on: ์„ ์ค„์—ฌ์„œ @์œผ๋กœ ์“ธ ์ˆ˜ ์žˆ๋‹ค!

ex)

09_v-on.html

<body>
    <div id="app">
        <h1>{{ message }}</h1>
        <button v-on:click="alertWarning"> Alert Warning </button>
        <button v-on:click="alertMessage"> Alert Message </button>
        <button @click="changeMessage"> Change Message </button>
        <hr/>
        <!-- enter key ๋ˆŒ๋ ธ์„ ๋•Œ event ๋ฐœ์ƒ-->
        <input v-on:keyup.enter="onKeyUp" type="text">
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data: { 
                message:'Hello Vue!'
            },
            methods: {
                alertWarning: function() {
                    alert('WARNING!')
                },
                alertMessage(){
                    alert(this.message)
                },
                changeMessage(){
                    this.message = 'Changed message'
                },
                onKeyUp(event) {
                    this.message = event.target.value
                }
            }
        })
    </script>
</body>

4-10. v-model

input, select, textarea ์—์„œ๋งŒ ๊ฐ€๋Šฅํ•œ ์–‘๋ฐฉํ–ฅ binding

  • v-model ๋””๋ ‰ํ‹ฐ๋ธŒ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํผ input๊ณผ textarea ์—˜๋ฆฌ๋จผํŠธ์— ์–‘๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค

  • v-model์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” โ€œsyntax sugarโ€ ๋‹ค

  • v-model์€ ๋ชจ๋“  form ์—˜๋ฆฌ๋จผํŠธ์˜ ์ดˆ๊ธฐ value์™€ checked ๊ทธ๋ฆฌ๊ณ  selected ์†์„ฑ์„ ๋ฌด์‹œํ•œ๋‹ค

    • ํ•ญ์ƒ Vue ์ธ์Šคํ„ด์Šค ๋ฐ์ดํ„ฐ๋ฅผ ์›๋ณธ ์†Œ์Šค๋กœ ์ทจ๊ธ‰

    • ์ปดํฌ๋„ŒํŠธ์˜ data ์˜ต์…˜ ์•ˆ์— ์žˆ๋Š” JavaScript์—์„œ ์ดˆ๊ธฐ๊ฐ’์„ ์„ ์–ธํ•ด์•ผํ•จ!

ex)

10_v-model.html

<body>
    <div id="app">
        <h1> {{ message }}</h1>
        <!-- ์‚ฌ์šฉ์ž ์ž…๋ ฅ <=> data๋ฅผ ์™„์ „ํžˆ ๋™๊ธฐํ™” ์‹œํ‚ค๊ณ  ์‹ถ๋‹ค! -->
        <!-- v-model => input, select, textarea ์—์„œ๋งŒ ๊ฐ€๋Šฅํ•œ ์–‘๋ฐฉํ–ฅ binding -->
        <hr/>
        <!-- ๋‹จ๋ฐฉํ–ฅ binding ( input => data )-->
        1way:
        <input @keyup="onInputChange" type="text">
        <hr/>
        <!-- ์–‘๋ฐฉํ–ฅ binding ( input <=> data )-->
        2way:
        <input @keyup="onInputChange" type="text" :value="message" />
        <hr/>
        <!-- v-model -->
        v-model/2way:
        <input v-model="message" type="text">
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                message: 'hi',
            },
            methods: {
                onInputChange(event){    
                    this.message = event.target.value
                }
            }
        })
    </script>
</body>

4-11. v-show

  • v-if ๋Š” ํ‰๊ฐ€(t/f) ๊ฐ€ ์ž์ฃผ ๋ฐ”๋€Œ์ง€ ์•Š์„ ๋•Œ ์œ ๋ฆฌํ•˜๋‹ค

  • => ์ดˆ๊ธฐ rendering cost๊ฐ€ ์ ๋‹ค

  • v-show๋Š” ํ‰๊ฐ€ (t/f)๊ฐ€ ์ž์ฃผ ๋ฐ”๋€” ๋•Œ ์ข‹๋‹ค

    • => toggle cost๊ฐ€ ์ ๋‹ค

    • v-show๋Š” ์ด๋ฏธ DOM ์— ์ค€๋น„ ํ•ด๋†จ๋Š”๋ฐ display๋งŒ none ์ž„!

ex)

11_v-show.html

<div id="app">
        <button @click="changeF">changeF</button>
        <p v-if="t">
            This is v-if with true
        </p>
        <p v-if="f">
            This is v-if with false
        </p>
        <p v-show="t">
            This is v-show with true
        </p>
        <p v-show="f">
            This is v-show wit false
        </p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data: {
                t: true,
                f:false,
            },
            methods: {
                changeF(){
                    this.f = !this.f
                }
            }
        })
    </script>
</body>

+

Lodash

A modern JavaScript utility library delivering modularity, performance & extras.

https://lodash.com/

CDN

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

Last updated

Was this helpful?