(준)공식 문서/Vue.js

[ Vue.js 3 공식 문서 ] 2. Essentials - Template Syntax

Je-chan 2022. 2. 18. 13:48

 

[ Reference ] 

https://vuejs.org/guide/essentials/template-syntax.html

 

Template Syntax | Vue.js

 

vuejs.org

 

 

  Vue 는 선언적 바인딩을 가능하게 하는 HTML 기반의 Template 구문을 사용한다. 모든 Vue template 은 HTML Parser 나 규격 호환 브라우저에서 파싱할 수 있는 유효한 HTML이다. Vue 는 template 을 높은 정도로 최적화된 자바스크립트 코드로 컴파일한다.

 

  여기에 반응성 시스템까지 겹쳐서 Vue 는 리렌더링 해야 하는 최소한의 Element 를 파악해 앱 상태가 변경될 때 최소한의 DOM 을 조작할 수 있도록 만든다. (* 의미하는 바를 잘 생각해보자. HTML 을 이용해서 DOM Tree 를 구성한다. 리렌더링은 이 DOM Tree 에 변화를 주는 것이고 리렌더링 하기 위해서는 자바스크립트 언어가 필요하다. 그렇기 때문에 반응성을 위해서 자바스크립트가 HTML을 바라보고 있어야 하는데, Vue 는 이것을 Template 을 통해서 구현하는 것이다.) 

 

  만약, Virtual DOM 에 익숙하고 순수 Javascript 의 기능들을 더 선호한다고 하면 Template 기능 대신에 선택적 JSX 지원을 받아 Render Functions 를 사용할 수 있다. 하지만 이 방법이  Vue 내부에서는 Template 과 동일한 정도의 컴파일 최적화를 지니진 못한다. (* 이 점이 Vue 와 React 의 큰 차이점인 것 같다)     

 

1. Text Interpolation

  데이터를 바인딩하는 가장 기초가 되는 방식은 Mustache(이중 중괄호) 를 이용해서 문자를 보간하는 방법이다.

 

<span>Message: {{ msg }}</span>

 

  이중 중괄호는 해 컴포넌트 내에서 msg 속성이 지니는 값으로 대체될 것이다. 그리고 반응성에 다라, msg 값이 바뀌게 되면 그때마다 리렌더링된다. 


2. Raw HTML

  이 이중 중괄호 방법은 HTML 이 아닌 일반 문자로 해석한다. 만약, HTML 로 반환을 하고 싶다면 ** v-html ** 이라고 하는 directive(디렉티브) 를 사용해야 한다. 

 

<p>Using text interpolation: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>

 

  v-html 과 같이 일반적으로 ** v- ** 로 시작하는 것들은 directive(디렉티브) 라고 한다. 디렉티브는 렌더링 된 DOM 에 특별한 반응을 보이도록 하기 위해 사용된다.  span 의 내용은 일반적인 HTML 값으로 대체되고 데이터 바인딩은 무시가 된다. Vue 는 문자열 기반의 템플릿 엔진이 아니다. 그렇기 때문에 v-html 을 사용해서 템플릿 부분을 구성할 수 없다. 특히 HTML 을 동적으로 렌더링 하는 행위 자체는 XSS 공격에 취약하다. 그렇기 때문에 웬만하면 자제하고 굳이 사용해야 한다면 신뢰할 수 있는 콘텐츠에서만 사용해야 한다. 


3. Attribute Bindings

  이중 중괄호는 HTML 속성 안에서 사용할 수 없다. 대신에 ** v-bind ** 라는 디렉티브를 이용해서 데이터를 HTML 속성 값에 바인딩할 수 있다.

 

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

 

  ** v-bind ** 디렉티브는 Vue 가 요소의 id 속성을 컴포넌트의 dynamicID 속성과 싱크를 맞추도록 한다. 만약 바인딩한 값이 null 이거나 undefined 가 될 경우, 속성은 리렌더링된 Element에 의해서 제거된다. 

 

  ** v-bind ** 는 굉장히 자주 쓰이는 디렉티브다 보니 축약형이 나왔다.

 

<div :id="dynamicId"></div>

 

  ** : ** 는 Vue 를 지원하는 브라우저에서 올바르게 파싱이 될 수 있고, 결과물로서 ** : ** 는 나타나지 않는다. 이렇게 축약하는 방식은 다른 디렉티브에서도 많이 사용하고 있기 때문에 나중에 제대로 한 번 공부하는 것이 좋다

 

  ** v-bind ( : ) ** 디렉티브를 이용하면 다양한 데이터들을 바인딩할 수 있다. 위에서 처럼 String 을 바인딩할 수도 있고,  Boolean 값이나 객체 등도 반환할 수 있다.


4. Using JavaScript Expressions

 

  ** v-bind ** 에 국한되지 않고 다양한 디렉티브와 이중 괄호문에서도 데이터를 바인딩할 때, 바인딩될 데이터는 JavaScript 로 표현할 수 있는 것이면 무엇이든 가능하다. 예를 들어 다음과 같은 것들도 바인딩할 수 있다.

 

{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }}

{{ message.split('').reverse().join('') }}

<div :id="`list-${id}`"></div>

  

 Expressions Only

  단, 오직 Expression 만 가능하다. 코드에서 Expression이란 어떤 값으로 표현될 수 있는 것들을 의미한다. 여기서 우리가 흔하게 아는 자료형들은 다 값으로 표현될 수 있기 때문에 모두 가능하다. 덧붙여서 사칙연산  1+1, 5 *5 도 사칙연산이 된 값을 표현할 수 있기 때문에 가능하다.

 

  하지만 아래와 같이 Statement(프로그래밍에서 실행이 가능한 코드를 의미하며, 변수 할당문과 같은 것들) 나 flow control 들은 바인딩이 될 수 없다(* 다만, 디렉티브에서 몇 가지 예외 사항이 존재한다). 우회적으로 조건식의 경우, if 를 이용해서 값을 바인딩할 수는 없지만 삼항 연산자를 사용하거나 단축 논리 평가법 ( &&, ||, ?? ) 의 경우에는 사용할 수 있다.

 

{{ var a = 1 }}

{{ if (ok) { return message } }}

 

Calling Functions

   반면, 함수는 가능하다. 함수 그 자체를 바인딩할 수는 없지만 함수를 실행했을 때, 어떤 값이 반환된다면 그 반환된 값은 표현될 수 있는 것이므로 사용이 가능하다. 다만 바인딩할 때 사용되는 함수는 구성 요소가 업데이트될 때마다 호출되는 함수이기 때문에 그 어떤 사이드 이펙트도 발생시키지 않는 순수 함수여야 한다. 즉, 비동기 함수는 사용할 수 없다는 얘기(* 물론, 여기서도 예외가 되는 디렉티브가 있다)

  

Restricted Global Access

  Template 표현 방식은 Sandbox 로 처리가 되므로 제한된 전역 목록에서만 액세스 할 수 있다. 전역 목록은 아래와 같다.

 

const GLOBALS_WHITE_LISTED =
  'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' +
  'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' +
  'Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt'

 

  위 목록에 표함되지 않은 전역은 template 표현에서 접근할 수 없다. 단, 위에서 정의되지 않은 글로벌 속성을 정의하고 싶다면 ** app.config.globalProperties ** 에서 명시적으로 정의해줄 수 있다. 


5. Diretives

  디렉티브는 ** v- ** 접두사가 붙는 특별한 속성이다. ** v-html **, ** v-bind** 를 포함해서 다양한 디렉티브들이 존재한다. 디렉티브 속성 값은 Single JavaScript Expressions 만 받아올 수 있다. (단, v-for, v-on, v-slot 은 제외로 한다) 디렉티브가 하는 일은 디렉티브의 속성 값이 업데이트됐을 때 DOM 에 업데이트를 적용하는 것이다. 

 

 

Arguments

  일부 디렉티브는 디렉티브 이름 뒤에 ** : **  이 붙고 다음에 오는 것은 Argument, 인자다. 

 

<a v-bind:href="url"> ... </a>

<!-- shorthand -->
<a :href="url"> ... </a>

 

Dynamic Arguments

  디렉티브 인자에 대괄호 ** [ ] ** 를 사용해서 자바스크립트 표현식을 사용할 수 있다. (* 이런 것들을 앞으로 이 블로그 내에서는 동적 인자라고 부르겠다. ...정확한 명칭인지는 모르겠다)

 

<a v-bind:[attributeName]="url"> ... </a>

<!-- shorthand -->
<a :[attributeName]="url"> ... </a>

 

  attributeName 은 자바스크립트의 표현식을 동적으로 계산을 한다. 그리고 그 계산된 값은 인자의 최종 값으로 바인딩된다. 무슨 말이냐면, 해당 컴포넌트 내에서 attributeName 이라는 것의 값이 href 라고 한다면, ** :[attributeName] ** 과 ** :href ** 는 동일하다는 말이다. 

 

Dynamic Argument Value Constraints

  다만, 동적 인자는 String 이나 null 이어야 한다. null 은 바인딩을 없애고자 할 때 사용할 수 있다. (* undefined 가 아님에 주의) 문자열이 아닌 경우에는 에러가 발생한다. 

 

Dynamic Argument Syntax Constraints

  첫 번째로 동적 인자로 표현하는데 공백, 따옴표 등과 같은 특정 문자는 HTML 의 속성 이름으로 사용되지 않기 때문에 그런 특정 문자에 대한 제약이 걸려 있다. 밑에 있는 것처럼 사용할 수 없다는 것

 

<a :['foo' + bar]="value"> ... </a>

 

  다만, 복잡한 동적 인자를 사용할 수 있는 방법으로 ** computed ** 라는 속성을 사용할 수 있다. (* 여기서 복잡하다는 건 'foo' + bar 와 같이 동적으로 계산이 들어가는 것을 의미한다. 그래서 computed 는 계산된 데이터를 저장하기 위해 사용한다고 한다. 

 

  두 번째로 in-DOM template 을 사용할 때 브라우저는 속성 이름을 소문자로 강제 전환하기 때문에 대문자로 이름을 지정해서는 안 된다. 예를 들면 밑에서 처럼 카멜 케이스로 작성하면 안 된다는 것

 

<a :[someAttr]="value"> ... </a>

 

  만약 위의 someAttr 라는 걸 어떻게든 쓰고 싶다면  someattr 로 모두 소문자로 변환해서 사용해야 한다.  

 

Modifiers

  Modifier 란 디렉티브 뒤에 ** . ** dot 을 사용해서 표시되는 것으로 앞에서 사용된 디렉티브가 반드시 특별한 방식으로 바운딩돼야 한다는 것이다. 예를 들어서 ** .prevent ** 라는 수식어는 v-on 디렉티브에서 event.preventDefault( ) 를 실행시키는 것과 동일하다. 

<form @submit.prevent="onSubmit">...</form>