cover

Vue에서 지원하는 디렉티브 뿐만 아니라 개발자가 원하는 기능이 들어간 디렉티브를 만들 수 있습니다.


커스텀 디렉티브 미리보기

커스텀 디렉티브 (Custom Directive)

Vue는 디렉티브(Directive)를 통해 이벤트처리를 하거나 조건에 따라 렌더링하는 등 다양한 기능을 제공합니다. 기본적으로 제공하는 디렉티브 대신 원하는 기능이 들어간 디렉티브를 만들 수 있습니다. 예를 들어 v-lazy라는 플러그인이 있습니다.

html
      <ul>
  <li v-for="img in list">
		<!-- 이미지를 lazy load 합니다. -->
    <img v-lazy="img.src" >
  </li>
</ul>
    

v-lazy 라는 커스텀 디렉티브를 통해 이미지를 lazy load합니다. 이렇게 자주 사용하는 기능들을 다시 사용하기 편하게 만들어주는 게 커스텀 디렉티브 역할입니다.

재사용성 높이는 방법들

디렉티브 뿐만 아니라 재사용성을 높이는 방법들이 있습니다. 바로 컴포넌트(Component)컴포저블(Composable)입니다. 이 둘과 같이 비교해보자면

컴포넌트(Component): UI와 기능, 스타일 들을 블록처럼 만들어 사용하는데 목적을 둡니다.
컴포저블(Composable): 상태를 가진 로직(stateful logic)을 재활용하는데 목적을 둡니다.
커스텀 디렉티브(Custom Directive): 컴포넌트가 아닌 기본 태그들에 접근해서 처리하는 로직을 재활용하는데 목적을 둡니다.

그래서 만약 간단하게 DOM에 접근해서 조작하는 정도라면 커스텀 디렉티브를 사용하는 방법을 추천합니다. 위에서 다룬 v-lazy가 좋은 예시입니다.

커스텀 디렉티브 등록하기

커스텀 디렉티브를 등록하는 방법은 두 가지가 있습니다.

1. 전역으로 등록하기
2. 로컬로 등록하기

전역으로 등록하기

Vue App의 directive 함수를 사용합니다.

javascript
      const app = createApp({});

// 모든 컴포넌트에서 v-focus를 사용 가능
app.directive('focus', {
	// ...
});
    

로컬로 등록하기

컴포넌트의 directives 속성을 사용합니다.

javascript
      export default {
  // 이 컴포넌트 내에서만 v-focus 사용 가능
  directives: {
    focus: {
			// ...
		}
  }
}
    

디렉티브 훅(Hook)

컴포넌트처럼 디렉티브도 고유한 훅(Hook) 함수가 존재합니다. 훅 함수는 특정 상황이 되었을 때 호출되는 함수입니다.

created: 태그 속성이 붙거나(bound) 이벤트 리스너가 적용되기 전에 호출됩니다.
beforeMount: DOM에 태그가 삽입되기 전에 호출됩니다.
mounted: 자식들이 모두 마운트되고 부모 컴포넌트에 바운드되면 호출합니다.
beforeUpdate: 부모 컴포넌트가 업데이트 되기전에 호출됩니다.
updated: 부모 컴포넌트와 자식들이 모두 업데이트 되고 호출됩니다.
beforeUnmount: 부모 커모넌트가 마운트 해제되기 전에 호출됩니다.
unmounted: 부모 컴포넌트가 호출 해제되면 호출됩니다.
javascript
      app.directive(name, {
	created(el, binding, vnode, prevVnode) {
	  binding.instance.logs.push("created");
	},
	beforeMount(el, binding, vnode, prevVnode) {
	  binding.instance.logs.push("beforeMount");
	},
	mounted(el, binding, vnode, prevVnode) {
	  binding.instance.logs.push("mounted");
	}
	beforeUpdate(el, binding, vnode, prevVnode) {
	  binding.instance.logs.push("beforeUpdate");
	},
	updated(el, binding, vnode, prevVnode) {
	  binding.instance.logs.push("updated");
	},
	beforeUnmount(el, binding, vnode, prevVnode) {
	  binding.instance.logs.push("beforeUnmount");
	},
	unmounted(el, binding, vnode, prevVnode) {
	  binding.instance.logs.push("unmount");
	}
});  
    

훅 함수 전달 인자

해당 훅 함수를 사용한다면 같이 오는 전달 인자들이 있습니다.

el: 디렉티브를 넣은 태그가 들어있습니다. 만약 <div v-my-directive></div>라면
image
binding: 다음 속성들이 들어있는 객체입니다.
value: 디렉티브에 넣은 값이 들어있습니다. 예를 들어 v-my-directive="1 + 1"라면, 2가 들어있습니다.
oldValue: 이전 값. 값이 변경되지 않더라도 사용가능합니다.
arg: directive에 전달된 인자가 들어있습니다. v-my-directive:foo라면 foo값이 들어있습니다.
modifiers: 수식어. v-my-directive.foo.bar라면 { foo: true, bar: true }가 들어있습니다.
instance: 디렉티브가 들어간 컴포넌트의 인스턴스가 들어있습니다.
dir: 디렉티브 정의 객체
image
vnode: 해당 태그의 VNode가 들어있습니다.
image
prevVnode: 해당 태그의 이전 VNode가 들어있습니다.
info
      el 값을 제외하고는 모두 읽는 용도로만 사용하고 수정하면 안됩니다. hook에서 데이터를 공유해야한다면 태그의 dataset을 사용해주세요.(data-…)
    

훅 함수 약식

mountedupdated는 동일한 동작을 하도록 하는 경우가 많습니다. 그러다보니 이를 줄여서 사용할 수도 있는데요.

html
      <div v-color="color"></div>
    

객체가 아닌 함수로 바로 넣을 경우 해당 함수는 mountedupdated 때마다 호출됩니다.

javascript
      app.directive('color', (el, binding) => {
  el.style.color = binding.value
})
    

컴포넌트에 사용하는 경우

컴포넌트를 사용하는 경우 컴포넌트의 최상단 태그에 자동적으로 들어갑니다. 하지만 Vue 3부터는 여러 태그가 들어갈 수 있게 되었습니다. 그런 경우 경고가 나타나면서 무시됩니다. 속성처럼 v-bind="$attrs" 방식으로 전달할 수 없기 때문에 컴포넌트에 커스텀 디렉티브를 사용하는 것은 권장하지 않습니다.