Vue의 데이터 바인딩에 대해서 알아보면서 v-bind라는 것도 알게 됐다.
정식 명칭은 디렉티브(Directives) 라고 한다.
번역하자면 지시문이고, HTML 태그 내의 속성으로 선언된다.
단순하게 'v-로 시작되는 속성을 가진 HTML 태그에 지시를 내린다'라고 생각하면 되겠다!
기본적으로 제공하는 디렉티브에 대해서 정리해봐야겠다.
- v-text
- v-html
- v-show
- v-if / v-else / v-else-if
- v-for
- v-on
- v-bind
- v-model
- v-slot
- v-pre
- v-cloak
- v-once
- v-is
15개나 있어서 간단하게나마 정리해봐야겠다.
1. v-text
<div id="app" v-text="txt"></div>
new Vue({
el: '#app',
data: {
txt: 'abcd'
}
});
엘리먼트의 textContent를 업데이트한다.
텍스트의 일부 수정이 있을 경우에는 Mustache Tag(이중 중괄호 문법) 를 활용해야 한다.
2. v-html
<div id="app" v-html="html"></div>
new Vue({
el: '#app',
data: {
html: '<p>Hi</p>'
}
});
엘리먼트의 innerHTML을 업데이트한다.
하지만 공식 홈페이지의 설명으로는 가급적 사용을 권장하지 않는 것 같다.
그 이유는 웹사이트에서 임의의 HTML을 동적으로 렌더링 하면 XSS 공격에 취약할 수 있기 때문이라고 한다.
v-html 디렉티브는 머릿속에서 지우는 걸로 해야겠다.
3. v-show
<div id="app" v-show="show">Hello</div>
new Vue({
el: '#app',
data: {
show: false
}
});
v-show는 표현식 값의 참-거짓을 기반으로 엘리먼트의 display CSS 속성을 전환한다.
표현식이 true면 보여주고 false면 숨긴다.
특징은 v-show를 사용한 엘리먼트는 DOM에 항상 렌더링은 되어 남아있고 display 속성만 변경한다는 점이다.
또한, v-show는 <template> 엘리먼트를 지원하지 않으며, v-else와 함께 쓸 수 없다고 한다.
화면에 숨겼다가 보여주는 작업이 있으면 자주 쓰일 것 같은 디렉티브이다.
4. v-if / v-else / v-else-if
<div id="app">
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
</div>
new Vue({
el: '#app',
data: {
type: 'A'
}
});
v-if는 표현식 값의 참-거짓에 따라 엘리먼트를 조건부로 렌더링 한다.
특징은 엘리먼트와 포함된 디렉티브/컴포넌트는 전환되는 동안 파괴되고 재구성되는 점이다.
엘리먼트가 <template> 엘리먼트인 경우 해당 컨텐츠가 조건부 블록으로 추출된다고 한다.
v-show와 다른 점은 렌더링의 차이와 <template> 지원 여부 일 것 같다.
또한, v-for와 함께 사용할 경우 v-if보다 v-for 우선순위가 높다고 한다.
v-else-if는 v-if 엘리먼트나 v-else-if 엘리먼트 바로 뒤에 있어야 인식이 되고
v-else는 v-if 엘리먼트와 v-else-if 엘리먼트 바로 뒤에 있어야 인식이 된다.
5. v-for
<div id="app">
<div v-for="item in items">
{{ item.text }}
</div>
</div>
new Vue({
el: '#app',
data: {
items: [{ text: 'Foo' }, { text: 'Bar' }]
}
});
v-for는 원본 데이터를 기준으로 엘리먼트 또는 템플릿 블록을 여러 번 렌더링 한다.
디렉티브의 값은 반복되는 현재 엘리먼트의 별칭을 제공하기 위해 특수 구문인 alias in expression 을 사용해야 한다.
또는, 아래와 같이 인덱스의 별칭(객체일 경우 키)을 지정할 수도 있다.
<div v-for="(item, index) in items"></div>
<div v-for="(value, key) in object"></div>
<div v-for="(value, name, index) in object"></div>
<div v-for="item in items" :key="item.id">
{{ item.text }}
</div>
배열과 객체를 별칭으로 자유롭게 반복적인 렌더링 작업을 할 수 있어서 v-for는 많이 쓰일 것 같다.
그리고 v-for에는 key라는 속성이 있는데 의도적인 경우를 제외하고는 언제나 key를 추가하는 것을 권장한다고 한다.
key 속성은 Vue가 노드를 식별할 수 있는 힌트로 사용되고 재정렬할 때 기준이 된다.
6. v-on
<!-- 메서드 핸들러 -->
<button v-on:click="doThis"></button>
<!-- 동적 이벤트 -->
<button v-on:[event]="doThis"></button>
<!-- 약칭 -->
<button @click="doThis"></button>
<!-- 자식컴포넌트 이벤트 수신 -->
<my-component @my-event="handleThis"></my-component>
v-on은 엘리먼트에 이벤트 리스너를 연결해준다.
동적으로 이벤트를 전달할 수도 있고 약칭 '@' 으로 표현할 수도 있다.
특징으로는 커스텀 엘리먼트 컴포넌트에서 사용될 경우 자식 컴포넌트에서 전달한 이벤트를 수신할 수 있다.
다양한 예제가 있겠지만 대표적인 예제만 알아보았다.
웹에서 이벤트 연결은 필수이므로 자주 쓰일 수밖에 없는 디렉티브 일 것이다.
7. v-bind
<!-- 속성 바인드 -->
<img v-bind:src="imageSrc" />
<!-- 동적 속성 이름 -->
<button v-bind:[key]="value"></button>
<!-- 약어 -->
<img :src="imageSrc" />
<!-- 자식컴포넌트로 데이터 전달 -->
<my-component :props="someThing"></my-component>
v-bind는 엘리먼트 속성을 바인딩할 수 있다.
속성은 동적으로도 전달이 가능하며 약칭 ':' 으로 표현할 수도 있다.
특징으로는 props 속성을 통해 데이터 바인딩하여 자식 컴포넌트로 전달이 가능하다.
v-on과 마찬가지로 자주 쓰일 수밖에 없는 디렉티브일 것이다.
8. v-model
<input v-model="message" placeholder="edit me" />
<p>메시지: {{ message }}</p>
v-model은 폼 입력 엘리먼트 또는 컴포넌트에 양방향 바인딩을 생성해준다.
폼 입력 엘리먼트는 input, select, textarea가 있고, 주로 input 태그와 함께 사용할 것 같다.
<!--
.lazy - input 대신에 change 이벤트를 수신
.number - 유효한 입력 문자열을 숫자로 캐스팅
.trim - 입력값을 트림(trim)처리
-->
<input v-model.lazy="msg" />
<input v-model.number="age" type="number" />
<input v-model.trim="msg" />
v-model의 특징은 위와 같은 수식어를 추가하여 유용한 기능을 사용할 수 있다는 점이다.
입력받는 곳이 많다면 자주 쓰일 것 같은 디렉티브이다.
9. v-slot
<todo-button>
Add todo
</todo-button>
<!-- todo-button 컴포넌트 템플릿 -->
<button class="btn-primary">
<slot></slot>
</button>
<!-- HTML 렌더링 -->
<button class="btn-primary">
Add todo
</button>
간단한 문자열 slot에 대한 예제이다.
만약 <todo-button> 컴포넌트의 템플릿이 <slot> 코드를 가지고 있지 않다면, 태그 내부에 위치한 모든 컨텐츠는 무시된다.
slot을 활용한다면 컴포넌트 내부의 컨텐츠를 전달하여 화면에 렌더링 할 수 있다.
<!-- 이름있는 슬롯(Named slots) -->
<base-layout>
<template v-slot:header>
Header content
</template>
<template v-slot:default>
Default slot content
</template>
<template v-slot:footer>
Footer content
</template>
</base-layout>
<!-- base-layout 컴포넌트 -->
<div class="container">
<header>
<slot name="header">
</header>
<main>
<slot>
</main>
<footer>
<slot name="footer">
</footer>
</div>
<!-- HTML 렌더링 -->
<div class="container">
<header>
<h1>Here might be a page title</h1>
</header>
<main>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</main>
<footer>
<p>Here's some contact info</p>
</footer>
</div>
v-slot은 이름이 있는 slot에 컨텐츠를 제공하기 위해 template 엘리먼트의 지시자로 사용된다.
약어로는 '#'을 사용하고 컴포넌트에 대한 이해와 사용도가 많으면 유용하게 사용할 수 있는 디렉티브일 것 같다.
10. v-pre
<span v-pre>{{ this will not be compiled }}</span>
v-pre는 다른 표현식 없이 사용되고
이 엘리먼트와 모든 하위 엘리먼트에 대한 컴파일을 건너뛴다고 한다.
원시 mustache 태그를 표시하는 데 사용할 수 있고
디렉티브가 없는 많은 노드를 건너뛰면 컴파일 속도가 빨라질 수 있다고 한다.
특별한 표현 없이 문자열만 있다거나 하는 곳에 사용하면 좋을 디렉티브인 것 같다.
11. v-cloak
[v-cloak] {
display: none;
}
<div v-cloak>
{{ message }}
</div>
v-cloak은 연결된 컴포넌트 인스턴스가 컴파일을 완료할 때까지 엘리먼트에 남아있다고 한다.
CSS 규칙과 함께 작성된 v-cloak은 컴포넌트 인스턴스가 준비될 때까지
컴파일되지 않은 mustache 바인딩을 숨기는 데 사용할 수 있다.
위 예제의 div 태그는 컴파일이 완료될 때까지 화면에 표시되지 않는다.
12. v-once
<!-- 단일 엘리먼트 -->
<span v-once>This will never change: {{msg}}</span>
<!-- 엘리먼트가 자식 엘리먼트를 가진 경우 -->
<div v-once>
<h1>comment</h1>
<p>{{msg}}</p>
</div>
<!-- 컴포넌트 -->
<my-component v-once :comment="msg"></my-component>
<!-- v-for 디렉티브 -->
<ul>
<li v-for="i in list" v-once>{{i}}</li>
</ul>
v-once를 사용한 엘리먼트와 컴포넌트는 한번(once)만 렌더링 된다.
이후에 재 렌더링 할 때는 엘리먼트, 컴포넌트, 모든 하위 엘리먼트는 정적 컨텐츠로 처리되고 건너뛰는 특징이 있다.
그러므로 업데이트 성능을 최적화하는 데 사용할 수 있을 것이다.
13. v-is
<!-- currentTabComponent가 변하면 컴포넌트가 바뀝니다. -->
<component :is="currentTabComponent"></component>
v-is는 3.1.0 버전 이후부터 더 이상 사용되지 않는다고 한다.
그 대신 is 속성을 사용하라고 설명되어있다.
is 속성을 통해서 동적으로 변하는 컴포넌트를 만들 수 있다.
기본적인 디렉티브이지만 중요한 부분도 많아서 하나씩 정리해보았다.
헷갈릴 때 한 번씩 찾아보면 좋을 것 같다!
'JavaScript > Vue.js' 카테고리의 다른 글
[Vue.js] 컴포넌트 통신(props, event emit) (0) | 2022.08.29 |
---|---|
[Vue.js] 데이터 바인딩(data binding) (0) | 2022.08.21 |
[Vue.js] Vue 시작하기 (0) | 2022.08.21 |