Vue.js | 문자 또는 목록 동적 표시

Vue.js 초기 설정 및 Vue를 사용하여 텍스트 또는 배열 등의 데이터를 동적으로 표시해 보도록 하자.

먼저 Vue.js를 사용할 수 있도록 한다.

  • Vue 2.5.4

연습으로 하고 싶은 경우에는 CDN을 이용하는 것이 가장 쉽다. 공식 사이트의 “시작하기“에 처음으로 소개되어 있다.

<script src="https://cdn.jsdelivr.net/npm/vue"></script>

이 URL은 항상 최신 버전을 개발 모드로 로드하여, 세세한 오류를 표시해 준다. 실제 운영에서는 min 파일을 사용하도록 한다.

로컬 환경 이외에도 https://jsfiddle.net을 이용하는 방법도 소개되어 있다. 예제을 시험하려는 경우 추천한다. 혹은, 본 싸이트 안에서도 샘플 마다 코드 실행가 있어서 바로 예제를 실행 시켜 볼 수도 있다.

Vue.js 반드시 Webpack 등의 빌드 환경을 필요로 하지 않기 때문에 쉽게 시작할 수 있다.

Vue 인스턴스를 만들기

먼저 최초에 Vue 생성자 함수를 사용하여 루트 인스턴스를 만든다.

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Vue Test</title>
</head>
<body>
  <div id="app">Hello {{ message }}</div>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script>
  var vm = new Vue({
    el: '#app',
    data: {
      message: 'Vue.js!'
    }
  })
  </script>
</body>
</html>

요소(element)가 없다고 경고가 나오는 경우에는 body 태그의 하단 등에 javascript를 작성하여 DOM이 로드된 후 실행하도록 한다. 변수로 두면, 다음과 같이 콘솔 또는 외부에서 액세스할 수 있다.

vm.message = "test"

생성자의 옵션에는 Vue.js에서 사용하는 데이터, 메소드, 마운트(배치) 요소 등을 지정할 수 있다.

  • el 마운트 요소의 선택
  • data Vue.js에서 취급하는 데이터
  • methods 응용 프로그램에서 사용하는 방법

언제 new Vue를 하는 것이 좋은가?

그런데, 이 Vue 생성자 함수는 어떤 태그에 사용하면 좋을까? 처음 사용하면 모를 것이다.

기본은 하나의 응용 프로그램, 예를 들어 블로그라면 블로그 전체에 Vue 루트 인스턴스를 하나 만들고, 구성 요소 부품을 늘려가는 방식이 좋다.

부품을 만드는 요소라는 기능이 있으므로, 메뉴와 폼과 같이 부품마다 new Vue하지는 않을 것이다. 그렇다면 구성 요소의 이용법은 거의 필수이므로 빨리 배우는 것이 좋을듯 싶다.

데이터는 속성으로 사용

뭔가 조작할 데이터는 옵션의 data를 정의하고 사용다.

new Vue({
  el: '#app',
  data: {
    message: 'Vue.js!' // ← 이 데이터를 사용한다.
  }
})

data에 등록된 데이터는 인스턴스 생성시 자동으로 반응(Reactive) 데이터로 변환된다. 반응 데이터가 되면, 데이터 그리기를 동기화 데이터 바인딩을 하거나, 그 뿐만 아니라 데이터의 변화에 따라 어떤 처리를 할 수도 있게 된다.

Vue에서 사용하는 템플릿을 로드할 때 일단 그리기 함수라는 일반 JavaScript 함수로 변환된다. 그리기 함수는 등록되어 있는 데이터의 상태를 바탕으로 가상 DOM을 구축하고, 가상 DOM의 상태는 비동기식으로 실제 DOM에 반영된다.

간단한 텍스트 표시

Vue에 정의된 데이터의 속성과 메소드는 그대로 같은 이름으로 템플릿을 사용하거나 실행할 수 있다

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Vue Test</title>
</head>
<body>
  <div id="app">
    <p>Hello {{ message }}</p>
  </div>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script>
  var vm = new Vue({
    el: '#app',
    data: {
      message: 'Vue.js!'
    }
  })
  </script>
</body>
</html>

코드 실행

데이터를 텍스트로 그리려면, 데이터의 이름을 {{ message }} 이렇게 두개 대괄호로 입력하여 템플릿을 작성한다. 이는 Mustache(머스테시)라는 기법으로 텍스트 콘텐츠의 일부로 데이터를 바인딩한다. 양쪽의 스페이스는 보기 쉽게 하기 위함이기에 없어도 된다.

위 예제는 루트에 message라는 데이터를 가지고 있기 때문에, 그 값 “Vue.js!“라는 텍스트가 그려진다.

메소드에서 데이터를 사용하는 경우는 this.message와 같이 this를 지정해야 합니다.

new Vue({
  el: '#app',
  data: {
    message: 'Vue.js!'
  },
  created: function() {
    alert(this.message)
  }
})

created은 라이프 사이클 메소드 중 하나이다.

데이터를 HTML으로써 표시하기

데이터 바인딩하여 데이터를 표시할 때에는 XSS 공격이 되지 않도록 HTML은 이스케이프(escapse) 처리가 된 텍스트로 표시한다. 신뢰할 수 있는 데이터를 HTML로 표시하려면 다음과 같이 작성해야 한다.

<span v-html="message"></span>

XSS는?

XSS 취약점을 쉽게 발생할 수 있기에 웹 사이트에서 동적으로 임의의 HTML을 렌더링하는 것은 매우 위험하다. 신뢰할 수 있는 컨텐츠만 HTML 표시를 해야 한다. 외부로 부터 제공된 입력값에 대해서는 표시하게 될 때에는 주의가 필요하다.

템플릿 구문

요소의 속성에 데이터를 사용하기

속성의 경우, 텍스트처럼 다음과 같이 작성해도 표시되지 않는다.

<p><a href="{{ url }}">{{ message }}</a></p> <!-- ★ 여기 URL는 표시되지 않는다 -->

속성에 데이터를 사용하려면, v-bind 지시어를 사용하여 바인딩해야 한다.

<p><a v-bind:href="url">{{ message }}</a></p>

또한 v-bind: 으로 생략할 수 있다. 바인딩시킬 개수가 많은 경우에 간략해 진다.

<p><a :href="url">{{ message }}</a></p>

이는 처음에는 인숙하지 않을 시에는 보기 힘들 수 있으니 v-bind를 넣어 주고 나중에 익숙해지면 생략하는 것이 좋을지도 있다.

일부을 Vue로 렌더링하지 않기

특정 요소 다음을 Vue에서 렌더링시킬 필요가 없는 경우도 있을 것이다. v-pre 지시어를 사용하면 일반 HTML라고 인식해 주므로 동적 콘텐츠를 포함하지 않는 경우 지정해 두면 성능이 오르기도 한다. v-once 지시문은 처음만 렌더링하고 그 이후에는 정적 컨텐츠로 처리된다. 나중에 message가 변경되어도 요소는 갱신되지 않는다.

어떠한 전개되지 않기 때문에 머스테시(mustache)의 상태 표시

<p><a v-bind:href="url" v-pre>Hello {{ message }}</a></p>

먼저 message를 표시한 이후 리 액티브 해제

<p><a v-bind:href="url" v-once>Hello {{ message }}</a></p>

코드 실행

정적 HTML 문장이나 표시한 후에는 모니터링 할 필요가 없는 경우에 성능 개선에 활용해 나가면 좋을 것 같다.

변경 사항을 실시간으로 반영하기

조금 순서가 빠르지만, 이런 프레임워크에서 샘플로 흔히 볼 수 있는 것이 변경 사항을 실시간으로 반영할 있는 폼을 작성해 보도록 하겠다. 이는 물론 jQuery와 평범하게도 할 수 있지만, 관리하는 것은 매우 귀찮을 일이다. 입력 양식과 데이터를 연결은 v-model 지시문을 사용한다.

<div id="app">
  <input v-model="message">
  <p>{{ message }}</p>
</div>

data 옵션에 message라는 데이터를 만들어 둔다.

new Vue({
  el: '#app',
  data: {
    message: '안녕하세요.'
  }
})

코드 실행

체크박스 또는 셀렉트 메뉴의 경우에는 어떻게 되는지 알고 싶겠지만, 이는 좀 더 기본을 배우고 나서 자세히 설명해 가도록 하겠다.

v-로 시작하는 지시문

지금까지도 v-bindv-html 등이 나왔지만, 앞으로 Vue.js 자체 특성인 v-로 시작하는 것이 다양하게 나올 것이다. 이것은 Vue.js에서 특별한 역할을 가진 속성으로 지시문(directive)이라고 한다. 그리고 v-로 시작하는 속성 값은 텍스트가 아닌 JavaScript 방식이라는 것이 포인트이다. 그 밖에도 Vue.js 자체의 특성은 있지만, v-로 시작하지 않는다면 기본적으로 값은 단순한 문자열이다. (slot-scope 제외) v-pre 등과 같이 값이 없는 것은 특별히 생각하지 않아도 된다.

목록 루프로 표시하기

조금 정교한 응용 프로그램을 만든다면 당연히 단순한 텍스트 뿐만이 아니기 때문에, 다양한 형식의 데이터를 정의하고 그것을 표시해 보도록 하자.

목록 표시

다음과 같이 list 라는 간단한 배열 데이터를 표시한다.

new Vue({
  el: '#app',
  data: {
    list: ['사과', '바나나', '딸기']
  }
})

목록을 표시하려면 v-for라는 지시문을 사용한다.

<div id="app4">
  <ul>
    <li v-for="val in list">{{ val }}</li>
  </ul>
</div>

v-for 지시문의 값은 보통 JavaScript로 루프에 사용하는 for..in 문과 비슷하지만, 실제 동작은 for..of에 가깝다.

코드 실행

객체 표시

다음과 같은 객체 데이터를 루프로 표시시켜 보도록 하겠다.

new Vue({
  el: '#app',
  data: {
    list: {
      a: '햄버거',
      b: '불고기',
      c: '파스타'
    }
  }
})

괄호를 사용하면 객체는 값과 키와 인덱스, 배열의 경우는 값과 인덱스를 임의로 받을 수 있다.

<div id="app">
  <ul>
    <li v-for="(val, key) in list">(Key:{{ key }}) {{ val }}</li>
  </ul>
</div>

객체의 처리 순서는 JSON 특성상 보장되지 않는다.

코드 실행

객체의 목록을 표시

다음에 중첩된 조금 복잡한 개체의 목록을 루프로 표시시켜 보도록 하겠다.

new Vue({
  el: '#app',
  data: {
    list: [
      { name: '토마토', price: 100 },
      { name: '양상추', price: 200 },
      { name: '오이', price: 300 }
    ]
  }
})

배열을 루프를 도는 것과 같으므로, 필요하지 않으면 인덱스는 취득하지 않아도 된다.

[코드 실행](/codes/29)

코드 실행

v-bind:key으로 ID와 같은 유니크 키를 지정해 두는 것이 추천하고 있다. 만약 이 리스트가 갱신될 때 렌더링 최적화를 하기에, 나중에 조작하고 싶다면 붙여두면 좋다. 향후에는 키의 지정이 필수가 될 수도 있다.

우선 다양한 종류의 데이터 표시하는 방법을 배웠다! 다음 장에서는 표시 데이터를 Vue를 사용하여 갱신해 보도록 하겠다.