logo
Search검색어를 포함하는 게시물들이 최신순으로 표시됩니다.
    Table of Contents
    [Vue] Vue.js instance 문법

    이미지 보기

    [Vue] Vue.js instance 문법

    • 22.05.04 작성

    • 읽는 데 15

    TOC

    Vue.js의 기본 문법

    Vue instance

    • 모든 Vue 앱은 Vue 함수로 새 인스턴스를 만드는 것부터 시작
    • Vue 인스턴스를 생성할 때는 Options 객체 전달
    • 여러 Options들을 사용하여 원하는 동작 구현
    • Vue Instance === Vue Component
    const app = new Vue({
    
    })
    

    Options/DOM

    Vue Instance의 Options 객체에서 DOM을 구성하는 요소들을 살펴보자.


    가. el

    • Vue 인스턴스에 연결(마운트)할 기존 DOM 요소 필요
    • CSS 선택자 문자열 or HTML Element로 작성
    • new를 이용한 인스턴스 생성 때만 사용
    const app = new Vue({
      el: '#app'
    })
    

    나. data와 methods

    • data : Vue 인스턴스의 데이터 객체, Vue 인스턴스의 상태 데이터 정의

    • methods : Vue 인스턴스에 추가할 메서드

    • Vue template에서 interpolation을 통해 접근 가능

    • v-bind, v-on과 같은 directive에서도 사용 가능

    • Vue 객체 내 다른 함수에서 this 키워드를 통해 접근 가능(this === 해당 vue 인스턴스)

    {%- raw -%}
    const app = new Vue({
      el: '#app',
      data: {
        message: 'Hello',
      },
      methods: {
        greeting: function () {
          console.log('hello')
        }
      }
    })
    {% endraw -%}
    

    주의📢 화살표 함수를 메서드 정의에 사용하지 않는다.

    화살표 함수가 부모 context를 binding하기 때문에 'this'가 Vue instance가 아니게 된다.


    Template 문법

    • 렌더링된 DOM을 기본 Vue 인스턴스의 데이터에 선언적으로 바인딩할 수 있는 HTML 기반 템플릿 구문 사용
    1. Interpolation
    2. Directive

    {%- raw -%}
    가. Text
    <span>메시지: {{ msg }}</span>
    
    나. Raw HTML
    <span v-html="rawHtml"></span>
    
    다. Attribute
    <div v-bind:id="dynamicId"></div>
    
    라. JS 표현식
    {{ number + 1 }}
    {{ message.split('').reverse().join('') }}
    {% endraw -%}
    

    Directive

    • v- 접두사가 있는 특수 속성
    • 속성 값은 단일 JS 표현식이 됨 (v-for은 예외)
    • 표현식의 값이 변경될 때 반응적으로 DOM에 적용하는 역할

    전달인자(Arguments)

    • :(콜론) 을 통해 전달인자를 받을 수 있음
    {%- raw -%}
    <a v-bind:href="url">...</a>
    <a v-on:click="dosomething">...</a>
    {% endraw -%}
    

    수식어(Modifiers)

    • .(점) 으로 표시되는 특수 접미사
    • directive를 특별한 방법으로 바인딩해야함을 의미
    {%- raw -%}
    <form v-on:submit.prevent="onSubmit"> ... </form>
    {% endraw -%}
    

    가. v-text

    • element의 textContent를 업데이트
    • 내부적으로 interpolation 문법이 v-text로 컴파일
    {%- raw -%}
    <p v-text="message"></p>
    <p>{{ message }}</p>
    {% endraw -%}
    

    위의 두 코드는 같다.


    나. v-html

    • element의 innerHTML을 업데이트
    • XSS 공격에 취약
    • 임의로 사용자로부터 입력 받은 내용은 v-html에 절대 사용 금지
    {%- raw -%}
    <div v-html="myHtml"></div>
    ...
    data: {
      myHtml: '<b>Hello</b>'
    }
    {% endraw -%}
    

    다. v-show

    • 조건부 렌더링 중 하나
    • 속성값은 boolean type data, true이면 display, false이면 display:none
    • 요소는 항상 렌더링, DOM에 있음
    • 단순히 element에 display 속성을 toggle
    {%- raw -%}
    <div id="app">
      <p v-show="isTrue">
        true
      </p>
      <p v-show="isFalse">
        false
      </p>
    </div>
    {% endraw -%}
    

    라. v-if, v-else-if, v-else

    • 조건부 렌더링 중 하나
    • directive의 표현식이 false라면 렌더링 자체가 되지 않음
    • element 및 포함된 directive는 toggle하는 동안 삭제되고 다시 작성
    {%- raw -%}
    <div id="app">
      <div v-if="myType === 'A'">
        A
      </div>
      <div v-else-if="myType === 'B'">
        B
      </div>
      <div v-else-if="myType === 'C'">
        C
      </div>
      <div v-else>
        Not A/B/C
      </div>
    </div>
    {% endraw -%}
    

    v-show와 v-if

    v-show (Expensive initial load, cheap toggle)

    • CSS display 속성을 hidden으로 만들어 toggle
    • 실제로 렌더링은 되지만 눈에 보이지 않음
    • 딱 한 번만 렌더링이 되는 경우 v-if에 비해 상대적으로 높은 렌더링 비용
    • 자주 변경되는 요소의 경우 한 번 렌더링된 이후 토글만 하면 되므로 비용 감소

    v-if (Cheap initial load, expensive toggle)

    • 전달인자가 false인 경우 렌더링 자체가 되지 않으므로 렌더링 비용 낮음
    • 자주 변경되는 요소의 경우 매번 다시 렌더링 해야하므로 비용 증가

    결론

    • 자주 변경될 거라면 v-show, 한 번만 쓸 거라면 v-if를 쓰자.
    • v-show는 안 보여도 렌더링, v-if는 안 보이면 렌더링 X

    마. v-for

    • 원본 데이터를 기반으로 element 또는 템플릿 블록을 여러 번 렌더링

    • item in items 구문 사용

    • item 위치의 변수를 각 요소에서 사용 가능

    • 객체의 경우 key

    • v-for 사용 시 반드시 key 속성을 각 요소에 작성

    • v-if와 함께 사용하는 경우 v-for가 우선순위가 더 높음

    • 단, 되도록 v-if와 v-for은 동시 사용 지양


    {%- raw -%}
    <body>
      <div id="app">
        <h2>String</h2>
        <div v-for="char in myStr">
          {{ char }}
        </div>
    
        <h2>Array</h2>
        <div v-for="fruit in fruits">
          {{ fruit }}
        </div>
    
        <div v-for="(fruit, idx) in fruits">
          {{ idx }} => {{ fruit }}
        </div>
    
        <div v-for="todo in todos" :key="todo.id">
          <p>{{ todo.title }} => {{ todo.completed }}</p>
        </div>
        
        <h2>Object</h2>
        <!-- value, key 순서임에 주의한다. -->
        <div v-for="(value, key) in myObj">
          {{ key }} => {{ value }}
        </div>
      </div>
    
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            myStr: 'Hello World!',
            fruits: ['apple', 'banana', 'coconut'],
            todos: [
              { id: 1, title: 'todo1', completed: true},
              { id: 2, title: 'todo2', completed: false},
              { id: 3, title: 'todo3', completed: true},
            ],
            myObj: {
              name: 'Smith',
              age: 25,
            }
          }
        })
      </script>
    </body>
    {% endraw -%}
    

    바. v-on

    • element에 EventListener 연결
    • 이벤트 유형은 전달인자로 표시
    • 특정 이벤트가 발생했을 때, 주어진 코드 실행
    • shorthand
      • @
      • v-on:click → @click

    {%- raw -%}
    <body>
      <div id="app">
        <!-- 메서드 핸들러 -->
        <!-- v-on:의 축약 : @ -->
        <button v-on:click="alertHello">Button</button>
        <button @click="alertHello">Button</button>
    
        <!-- 기본 동작 방지 -->
        <!-- @submit.prevent -->
        <form action="" @submit.prevent="alertHello">
          <button>GoGo</button>
        </form>
    
        <!-- 키 별칭을 이용한 키 입력 수식어 -->
        <!-- space, enter 등을 keyup 했을 때에만 함수 실행 -->
        <input type="text" @keyup.enter="log">
    
        <!-- callback 함수에서의 특수문법 () -->
        <!-- 'a'를 인자로 넣어 바로 실행한다. 라는 의미가 아닌, --> 
        <!-- 실행할 때 1번 인자를 'a'로 넣겠다는 의미 --><input type="text" @keyup.enter="log('a')">
    
        <p>{{ message }}</p>
        <button @click="changeMessage">change message</button>
      </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: {
            alertHello: function () {
              alert('hello')
            },
            log: function (event) {
              console.log(event)
            },
            changeMessage() {
              this.message = new Date()
            }
          }
        })
      </script>
    </body>
    {% endraw -%}
    

    사. v-bind

    • HTML 요소의 속성에 Vue의 상태 데이터를 값으로 할당
    • Object 형태로 사용하면 value가 true인 key가 class 바인딩 값으로 할당
    • shorthand
      • :(colon)
      • v-bind:href => :href
    {%- raw -%}
    <head>
      ...
      <style>
        .active {
          color: red;           
        }
    
        .my-background-color {
          background-color: yellow;
        }
      </style>
    </head>
    <body>
      <!-- v-bind : 기본 속성이라 v-가 안되는 속성들을 v-와 엮어주는 방법 -->
      <div id="app">
    
        <!-- 속성 바인딩 -->
        <!-- <img v-bind:src="imageSrc" alt=""> -->
        <img :src="imageSrc" alt="">
        <hr>
    
        <!-- 클래스 바인딩 -->
        <!-- isRed가 true일 때만 active 클래스 활성화하겠다. -->
        <div :class="{ active: isRed }">
          클래스 바인딩
        </div>
        <hr>
    
        <h3 :class="[activeRed, myBackground]">
          hello vue
        </h3>
    
        <!-- 스타일 바인딩 -->
        <p :style="{ fontSize: 20px }">
          this is 
        </p>
      </div>
      
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            fontSize: 16,
            altMsg: 'this is image',
            imageSrc: 'https://picsum.photos/id/310/200/300',
            isRed: true,
            activeRed: 'active',
            myBackground: 'my-background-color',
          }
        })
      </script>
    {% endraw -%}
    

    아. v-model

    • HTML form 요소의 값과 data를 양방향 바인딩
    • 수식어
      • .lazy : input 대신 change 이벤트 이후에 동기화
      • .number : 문자열 → 숫자
      • .trim : 입력에 대한 trim 진행
    {%- raw -%}
    <body>
      <div id="app">
        <h2>Input -> Data 단방향</h2>
        <p>{{ msg1 }}</p>
        <input type="text" @input="onInputChange">
        <hr>
    
        <h2>Input <-> Data 양방향</h2>
        <p>{{ msg2 }}</p>
        <input type="text" v-model="msg2">
    
        <hr>
    
        췤! <input id="box" type="checkbox" v-model="checked">
        <label for="box">{{ checked }}</label>
    
    
    
    
      </div>
    
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            msg1: '111',
            msg2: '222',
            checked: true,
          },
          methods: {
            onInputChange (event) {
              this.msg1 = event.target.value
            },
          },
        })
      </script>
    </body>
    {% endraw -%}
    

    Options/Data

    computed

    • 데이터를 기반으로 하는 계산된 속성
    • 함수의 형태로 정의 BUT 함수의 반환값이 바인딩
    • computed 구성을 위해 종속된 데이터에 따라 저장(캐싱)
    • 종속된 데이터가 변경될 때만 함수 실행
    • 어떤 데이터에도 의존하지 않는 computed 속성의 경우 불변
    • 반드시 반환값이 있어야 한다.
    {%- raw -%}
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            r: 2,
            // area: 2*2*3.14,
            // perim: 2*2*3.14,
          },
          computed: {
            area: function () {
              return this.r ** 2 * 3.14
            },
            perim: function () {
              return 2 * this.r * 3.14
            },
          }
          // watch: {
          //   area: function () {
          //     this.area = this.r * this.r * 3.14
          //   }
          //   perim: function () {
          //     this.perim = 2 * this.r * 3.14
          //   }
          // }
        })
      </script>
    {% endraw -%}
    

    computed와 methods

    • computed 속성 대신 methods에 함수를 정의 가능

    • 최종 결과에 대해 두 가지 접근 방식은 서로 동일

    • 차이점은 computed 속성은 종속 대상을 따라 저장(캐싱)

    • computed는 종속된 대상이 변경되지 않는 한 computed에 작성된 함수를 여러 번 호출해도 계산을 다시 하지 않고 계산되어 있던 결과 반환

    • ⭐ 요약 : 변경 없이 여러 번 호출 → methods는 매번 함수 실행, computed는 재계산 없이 캐시값 반환

    {%- raw -%}
    <script>
      const app = new Vue({
        el: '#app',
        data: {
          sessionId: '',
          message: 'Original'
        },
        // render될 때마다 함수를 재실행
        // -> data를 바꾸는 로직 위주 (setter)
        methods: {
          reverseMessage () {
            return this.message.split('').reverse().join('')
          }
        },
        // (data에 의존하는) 계산된 값
        // 종속 대상을 따라 저장(캐싱)된다.
        // data를 통해 값을 얻는 경우 사용 (getter)
        computed: {
          reversedMessage () {
            return this.message.split('').reverse().join('')
          },
          isLoggedIn () {
            // sessionId의 변화가 없다면 언제 호출되어도 캐시값 반환
            return this.sessionId ? true : false
          }
        },
      })
    </script>
    {% endraw -%}
    

    watch

    • 데이터를 감시
    • 데이터에 변화가 일어났을 때 실행되는 함수
    {%- raw -%}
    const app = new Vue({
      el: '#app',
      data: {
        num: 2,
      },
      watch: {
        num: function () {
          console.log(`${this.num}이 변경되었습니다.`)
        }
      },
    })
    {% endraw -%}
    
    • this.num(내부 종속 대상)이 바뀌면 num 함수 실행
    • react의 useEffect와 같다.

    computed와 watch

    computed

    • 특정 데이터를 직접적으로 사용/가공 → 다른 값으로 만들 때 사용
    • 종속 데이터의 원본 값은 바꾸지 않고 새로운 값을 '계산'하는 것
    • 속성은 계산해야 하는 목표 데이터를 정의하는 방식
    • "A 값이 A2로 변하면 이전에 A로부터 계산됐던 B 값을 다시 계산해 B2 값을 만들어 보여준다."
    • 선언형 프로그래밍 방식 → "계산해야 하는 목표 데이터 정의"

    watch

    • 특정 데이터의 변화 상황에 맞춰 다른 data 등이 바뀌어야 할 때 사용
    • 감시할 데이터를 지정, 해당 데이터가 바뀌면 특정 함수 실행
    • "A 값이 변하면 B 함수를 실행해 작업한다."
    • 특정 대상이 변경되었을 때 콜백 함수를 실행시키기 위한 트리거
    • 명령형 프로그래밍 방식 → "데이터가 바뀌면 특정 함수 실행해!"

    filter

    • 텍스트 형식화를 적용할 수 있는 필터
    • interpolation 혹은 v-bind를 이용할 때 사용 가능
    • JS 표현식의 마지막에 |(pipe)와 함께 추가
    • chaining 가능
    {%- raw -%}
    <body>
      <div id="app">
        <div>{{ numbers }}</div>
        <div>{{ numbers | getOddNumbers }}</div>
        <div>{{ numbers | getOddNumbers | getUnderTen }}</div>
        <div>{{ getOddAndUnderTen }}</div>
      </div>
    
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
          },
          filters: {
            getOddNumbers(array) {
              return array.filter(num => num % 2)
            },
            getUnderTen(array) {
              return array.filter(num => num < 10)
            }
          },
          computed: {
            getOddAndUnderTen() {
              return this.numbers.filter(num => num%2 && num<10)
            }
          }
        })
      </script>
    </body>
    {% endraw -%}
    
    profile

    FE Developer 박승훈

    노력하는 자는 즐기는 자를 이길 수 없다