Vue 템플릿 신텍스

Vue.js는 HTML 기반의 템플릿 문법을 제공한다.
이는 선언적으로 DOM에 Vue instance data를 바인딩할 수 있게 해준다.

모든 Vue.js 템플릿은 스펙을 호환하는 브라우저와 HTML 파서로 구문을 분석할 수 있는 유효한 HTML이다.

💡 내부적으로 Vue는 템플릿을 가상 DOM 렌더링 함수로 컴파일한다.
반응형 시스템과 결합하여, 뷰는 앱의 상태가 변화할 때 리렌더링해야할 최소한의 컴포넌트를 찾아서, 최소한의 DOM 조작을 하게 된다.

그냥 JS로 하고 싶으면, 템플릿 대신에 렌더링함수를 직접 작성할 수 있다. 선택사항으로 JSX를 지원한다.

🖍 Interpolation 보간법

Text : {{ }}

가장 기본적인 데이터 바인딩의 형태는 "Mustache" 신택스를 사용한 텍스트 보간법이다.
"Mustache" 신택스는 중괄호를 사용한다.

<span>{{msg}}</span>

mustache 태그는 데이터 객체의 msg 프로퍼티의 값으로 대체될 것이다.
또한, msg 값이 변화할 때마다 업데이트된다.

v-once 디렉티브를 사용하면, 데이터가 변화하여도 업데이트가 안되게 할 수 있다.
그러나, 이는 같은 노드에 있는 다른 바인딩에도 영향을 준다는 것을 유의해야 한다.
❓ 이거 무슨말인지 모르겠다!

<span v-once>절대 변하지 않는 값 -> {{msg}} 왜냐면 v-once 디렉티브를 썼기 때문에!</span>

Raw HTML : v-html

double mustaches는 데이터를 플레인 텍스트로 해석한다.
만약, HTML로 해석해야 한다면, v-html 디렉티브를 사용해야 한다.

const vm = new Vue({
  el: '#app1',
  data: {
    rawHtml: `<span style="color:red">빨간색 글씨가 나와야 한다.</span>`,
  },
});

<div id="app1"> <p>mustaches : {{ rawHtml }}</p> <p>v-html : <span v-html="rawHtml"></span></p> </div>

span의 컨텐츠는 rawHtml 프로퍼티의 값으로 대체되며, 플레인 HTML로 해석된다. 이 때, 데이타 바인딩은 무시된다. (❓ 모르겠음.)

v-html을 템플릿을 사용하는데 사용해서는 안된다. 뷰는 스트링 기반의 템플릿 엔진이 아니기 때문이다. 그 대신에, 컴포넌트를 사용할 것을 권한다. 컴포넌트는 UI 재사용과 구성의 기본 단위로 쓰이게 된다.

⚠️ 동적으로 임의의 HTML이 렌더링 되는 것은 매우 위험하다. 이는 XSS 취약점으로 쉽게 이어질 수 있기 때문이다. HTML 보간법은 신뢰할 수 있는 컨텐츠에만 사용하고, 절대 사용자가 제공하는 컨텐츠에는 사용하지 않아야 한다.

❓ XSS 취약점?

Attributes 속성 : v-bind

mustaches는 html 속성 안에 사용될 수 없다.
대신, v-bind 디렉티브를 사용하면 된다.

<div v-bind:id='dynamicId'></div>

boolean 속성을 사용할 때, 조금 다르게 동작한다.
여기서 isButtonDisabled가 null, undefined, false일 경우에는
disabled 속성이 <button> 엘리먼트에 포함되지도 않는다.

  • isButtonDisabled가 true일 경우

    disabled 속성이 포함되었음을 확인할 수 있다.

  • isButtonDisabled가 undefined인 경우

    disabled 속성이 포함되지 않은 것을 확인할 수 있다.

Javascript Expression

Vue는 데이터 바인딩 안에 JS expression을 완전히 지원한다.

const app3 = new Vue({
  el: '#app3',
  data: {
    number: 100,
    ok: false,
    message: '안녕하세요',
    id: 10,
  },
});
<div id="app3"> 
  <div v-bind:id="'list-' + id">check out id</div>
  number : {{ number + 1}}
  {{ok ? 'yes' : 'no'}}
  {{message.split('').reverse().join('')}}
</div>

단, 각 바인딩마다 하나의 expression만 포함되어야 한다.

다음은 동작하지 않는 경우이다.

<!-- 이는 expression이 아닌 statement이다. -->
{{ var a = 1 }} 

<!-- flow control도 동작하지 않는다. 삼항연산자를 사용해야 한다.-->
{{ if(ok) {return message} }} 

⚠️ 템플릿 expression은 샌드박스되어있고, Math, Date와 같은 whitelist of globals에만 접근할 수 있다. 템플릿 expression 안에서 사용자 정의 전역 변수에 접근하면 안된다.

const allowedGlobals = makeMap( 'Infinity,undefined,NaN,isFinite,isNaN,' + 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' + 'require' // for Webpack/Browserify )

🖍 Directives 디렉티브

디렉티브는 v-를 접두사로 갖는 속성이다.
디렉티브 속성의 값은 하나의 JS Expression이어야 한다. (v-for은 예외)

디렉티브의 역할은 expression의 값이 변경되었을 때, reactively 사이드 이펙트를 DOM에 적용시키는 것이다.

<p v-if="seen">Now you see me</p>

v-ifseen의 값이 true인지 false인지에 따라서 , <p> 엘리먼트를 DOM에 추가하거나 삭제할 것이다.

Arguments 전달인자

어떠한 directive는 argument를 가질 수 있다. 이 argument는 디렉티브 이름 옆에 콜론으로 표시된다.

예를 들어, href는 argument인데, 이는 v-bind 디렉티브에게 href 속성의 값을 url로 바인드해야함을 말해준다.

<div id="app4"> 
  <a v-bind:href="url">kakao for business</a>
</div>
const app4 = new Vue({
  el: '#app4',
  data: {
    url: 'https://business.kakao.com/',
  },
});

v-on 디렉티브는 DOM 이벤트를 리스닝하고 있다.

여기서 argument는 리스팅하고 있는 이벤트이다.

<div id="app5"> 
  <button v-on:click='alertHi'>click me!</button>
</div>
const app5 = new Vue({
  el: '#app5',
  data: {
    alertHi() {
      alert('hi');
    },
  },
});

dynamic arguments 동적 전달인자

2.6.0 버전부터, 대괄호(square bracket)에 감싼 JS expression을 디렉티브의 argument로 사용하는 것이 가능해졌다.

<!-- Note that there are some constraints to the argument expression, as explained in the "Dynamic Argument Expression Constraints" section below. --> <a v-bind:[attributeName]="url"> ... </a> <a v-on:[eventName]="doSomething"> ... </a>

attributeNameeventName은 vue instance에 있을 data 프로퍼티의 값으로 대체된다.

  • 동적 전달인자의 제약
    동적 전달인자는 null을 제외하고는 string으로 변환되기를 기대한다. 따라서, string이 아닌 값은 경고가 띄워지게 된다. null은 명시적으로 바인딩을 제외할 때 사용된다.

-> 사용방식을 더 살펴봐야 할 것 같ㄷ.

수식어

수식어는 디렉티브를 특별한 방식으로 바인딩해야 함을 나타낸다.
예를들어 .prevent가 붙으면, 그 이벤트는 event.preventDefault()를 호출하도록 v-on 디렉티브에게 알려주어야 한다.

🖍 약어

가장 자주 사용되는 v-bindv-on에 약어가 있다.

  • v-bind 약어 : v-bind를 삭제

    ​​​​<!-- 전체 문법 -->
    ​​​​<a v-bind:href="url"> ... </a>
    
    ​​​​<!-- 약어 -->
    ​​​​<a :href="url"> ... </a>
    
    ​​​​<!-- shorthand with dynamic argument (2.6.0+) -->
    ​​​​<a :[key]="url"> ... </a>
    
  • v-on 약어 : @eventName

    ​​​​<!-- 전체 문법 -->
    ​​​​<a v-on:click="doSomething"> ... </a>
    
    ​​​​<!-- 약어 -->
    ​​​​<a @click="doSomething"> ... </a>
    
    ​​​​<!-- shorthand with dynamic argument (2.6.0+) -->
    ​​​​<a @[event]="doSomething"> ... </a>
    
Select a repo