/ #JAVASCRIPT#VUE.JS

Vue.js: directive (1)

디렉티브(Derectives)

디렉티브(Directives)는 번역하자면 지시문이라고 할 수 있습니다. 지난번 텍스트 보간에 사용한 v-text 디렉티브처럼 Vue의 디렉티브에는 v- 라는 접두사가 붙습니다. 디렉티브를 HTML 템플릿 구문의 속성으로 작성하면 해당 지시문이 DOM에 적용됩니다.

디렉티브는 Vue에서 제공하는 내장 디렉티브(Built-in Directives)와 사용자가 만들어서 사용하는 커스텀 디렉티브(Custom Directives)가 있습니다.

이번 글에서는 Vue에서 기본적으로 제공하는 내장 디렉티브에 대해서 알아보겠습니다.

v-html

지난번에 텍스트 보간에 v-text를 사용했습니다. 만약 v-text를 사용하여 html 태그를 작성한다면 DOM이 생성되는 것이 아니라 텍스트 자체가 출력됩니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app" v-text="html"></div>
</body>
</html>
main.js
const mv = new Vue({
  data: {
    html: `<font color="red">Red Color</font>`
  }
}).$mount('#app')
출력 결과

img009

하지만 v-html 디렉티브를 사용하면 html 템플릿을 통해 DOM을 생성합니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app" v-html="html"></div>
</body>
</html>
출력 결과

img010

동적으로 html을 렌더링 하는 것은 XSS 공격을 받을 가능성이 있기때문에 해당 디렉티브는 입력할 내용을 신뢰할 수 있을 경우에만 사용할 것을 권장합니다.

v-bind

v-bind는 태그 속성에 모델 데이터를 바인딩하거나 자식 컴포넌트에 프로퍼티를 전달할 때 사용합니다. 컴포넌트는 다음에 알아보도록 하고 우선 속성을 바인딩 하겠습니다.

속성 바인딩은 v-bind:[key] = "value" 형태로 작성합니다. 예를 들어 id 속성에 id 데이터를 바인딩 하려면 다음과 같이 작성합니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app" v-bind:id="id"></div>
</body>
</html>
main.js
const mv = new Vue({
  data: {
    id: 'bindingTest'
  }
}).$mount('#app')

DevTools를 통해 DOM 태그를 확인하면 id가 모델에 입력된 id값 bindingTest가 되었음을 확인할 수 있습니다.

출력 결과

img011

해당 디렉티브는 :[key] = "value" 형태로 줄일 수 있습니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app" :id="id"></div>
</body>
</html>

class 속성의 경우 Object 타입으로 다중 속성을 바인딩할 수 있습니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app" :class="{a: true, b: true, c: false}"></div>
</body>
</html>
main.js
const mv = new Vue().$mount('#app')
출력 결과

img012

다음과 같이 속성을 각각 바인딩 할 수도 있습니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app" :class="{a, b, c}"></div>
</body>
</html>
main.js
const mv = new Vue({
  data: {
    a: true,
    b: true,
    c: false
  }
}).$mount('#app')

한번에 Object 타입을 바인딩할 수도 있습니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app" :class="classObj"></div>
</body>
</html>
main.js
const mv = new Vue({
  data: {
    classObj: {
      a: true,
      b: true,
      c: false
    }
  }
}).$mount('#app')

배열로 바인딩할 수도 있습니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app" :class="['a', 'b']"></div>
</body>
</html>
main.js
const mv = new Vue().$mount('#app')

Object를 배열로 바인딩하여 클래스 속성을 합칠 수도 있습니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app" :class="[{a: true}, {b: true}, {c: false}]"></div>
</body>
</html>

style 속성 또한 class 속성과 유사합니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app" :style="styleObj"></div>
</body>
</html>
main.js
const mv = new Vue({
  data: {
    styleObj: {
      fontSize: '20px',
      'font-weight': 'bold',
      color: 'red'
    },
    message: 'hello, world!'
  }
}).$mount('#app')
출력 결과

img013

키값을 카멜 케이스(Camel Case)로 선언하면 스타일 속성이 케밥 케이스(Kebab Case)로 변경됩니다.

styleObj에 선언한 fontSize가 자동으로 font-size 속성으로 변경된 것을 확인할 수 있습니다.

v-if / v-else-if / v-else

조건에 따라 DOM을 렌더링하고 싶다면 v-if 디렉티브를 사용합니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app">
    <span v-if="isNotice"></span>
  </div>
</body>
</html>
main.js
const mv = new Vue({
  data: {
    notice: 'notice',
    isNotice: true
  }
}).$mount('#app')

isNotice가 true이므로 조건식을 만족하여 해당 DOM은 렌더링되어 나타납니다.

출력 결과

img014

콘솔창을 통해 isNotice를 false로 변경한다면 조건식을 만족하지 못하여 해당 DOM은 사라집니다.

출력 결과

img015

처음 조건을 만족하지 못했을때 다른 조건문을 만족하는지 확인하고 싶다면 v-else-if 디렉티브를, 조건문을 만족하지 못했을 경우에 출력하고 싶다면 v-else 디렉티브를 사용합니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app">
    <font v-if="color === 'red'" color="red">red</font>
    <font v-else-if="color === 'blue'" color="blue">blue</font>
    <font v-else>default</font>
  </div>
</body>
</html>
main.js
const mv = new Vue({
  data: {
    color: 'red',
  }
}).$mount('#app')
출력 결과

img016

여러 태그를 한꺼번에 묶어서 조건문을 처리하고 싶다면 template 태그에 v-if 디렉티브를 입력하면 됩니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app">
    <template v-if="isNotice">
      <div>1</div>
      <div>2</div>
      <div>3</div>
    </template>
  </div>
</body>
</html>
main.js
const mv = new Vue({
  data: {
    isNotice: true
  }
}).$mount('#app')

이 경우 template 태그는 렌더링 되지 않게 됩니다.

출력 결과

img017

v-for

반복문의 경우 v-for 디렉티브를 입력하면 됩니다. 배열, map, set 등 iterable 객체 및 Object 타입에 대한 반복문 작성이 가능합니다.

v-for 디렉티브 선언
<div v-for="(item, index) in items"></div>
<div v-for="(value, key) in object"></div>
<div v-for="(value, key, index) in object"></div>

예제는 아래와 같습니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app">
    <div v-for="(member, idx) in members" :key="member.id">
      <div>index: </div>
      <div>id: </div>
      <div>name: </div>
    </div>
  </div>
</body>
</html>
main.js
const mv = new Vue({
  data: {
    members: [
      {id: 'rubisco', name: '루비스코' },
      {id: 'spot', name: '스팟'}
    ]
  }
}).$mount('#app')

중요한 부분은 key 속성을 바인딩 했다는 것입니다. key는 primary key를 바인딩하여 각각의 요소들에 대한 순서에 대하여 힌트를 줄 수 있도록 합니다.

출력 결과

img018