본문 바로가기
front/vue

[vue3 공식문서 번역]Reusability.2.Custom Directives

by juniKang 2022. 5. 5.

소개

v-model이나 v-show같은 core에 적재된 기지시어의 기본 집합에 더해, 뷰는 커스텀 지시어 등록을 허락한다.

 

뷰에서 코드 재사용의 두가지 방법을 소개했다: components 와 composables이다. 컴포넌트는 주요 빌딩 블록이다. 반면 composables는 상태가 있는 로직의 재사용에 중점을 뒀다. 커스텀 지시어는 반면에, 순수한 엘리먼트의 밑단 DOM 접근을 포함하는 재사용로직을 주로 다룬다.

 

커스텀 지시어는 컴포넌트의 그것과 비슷하게 라이프사이클 훅을 담은 객체로 정의된다. 훅은 지시어가 바운드되는 에릴먼트를 제공한다. 엘리먼트가 뷰에의해 돔에 삽입됐을 때의 인풋을 focus하는 지시어의 예제이다:

<script setup>
// 템플릿에서 v-focus사용을 가능 하게 함
const vFocus = {
  mounted: (el) => el.focus()
}
</script>

<template>
  <input v-focus />
</template>

페이지에서 어딘가를 누르지 않으면, 인풋은 자동으로 포커스된다. 이 지시어는 autofoucs 어트리뷰트보다 더 유용하다. 왜냐면, 페이지 로드에만 작동하는게 아니기 때문이다. 이건 엘리먼트가 뷰에의해 동적으로 삽입되었을 떄도 동작한다. 

 

<script setup>에서 , v 접두어로 시작하는 모든 camelCase 변수는 커스텀 지시어로 사용될 수 있다. 위예 예에서는, vFocus는 v-focus로 사용가능했다.

 

<script setup>을 사용하지 않으면, 커스텀 지시어는 deirectives 옵션을 사용해서도 등록 될 수 있다:

export default {
  setup() {
    /*...*/
  },
  directives: {
    // template에서 v-focus로 사용가능함
    focus: {
      /* ... */
    }
  }
}

앱 레벨에서 커스텀 지시어를 전역적으로 등록하는 것은 흔하다:

const app = createApp({})

// v-focus를 모든 컴포넌트에서 사용할 수 있다.
app.directive('focus', {
  /* ... */
})

Directive Hooks

지시어를 정의한 객체는 여러 훅 함수를 제공할 수 있다( 모두 선택적인):

const myDirective = {
  // 엘리먼트의 어트리뷰트를 바인드 하기 전 호출
  // 또는 이벤트리스너가 적용되면 호출
  create(el, binding, vnode, prevVnode) {
    // 아규먼트에 대해서는 아래 참조
  },
  // 엘리먼트가 돔에 삽입되기 직전 호출
  beforeMount() {},
  // 바운드 엘리먼트의 부모 컴포넌트와 모든 그 자식들이 mounted되었을 때 호출
  mounted() {},
  // 부모 컴포넌트가 업데이트 되기 전에 호출
  beforeUpdate() {},
  // 부모 컴포넌트와 모든 자식 들이 업데이트 된 후에 호출
  update() {},
  // 부모 컴포넌트가 unmounted 되기 전에 호출
  beforeUnmount() {},
  // 부모 컴포넌트가 unmounted 되었을 때 호출
  unmounted() {}
}

Hook Arguments

지시 훅들은 이 아규먼트들을 받는다 :

  • el : 지시어가 바운드되는 element. 직접적으로 돔을 조작하는 일에 사용됨
  • binding : 다음 프로퍼티들을 담고있는 객체
    • value : 지시어로 전달하는 값. 예를들어 v-my-directive="1 + 1" 은 2가 된다.
    • oldValue : 이전 값, beforeUpdate 나 updated만 가능하다. value가 바뀌든 바뀌지 않든 가능하다.
    • arg : 지시어로 전달받은 아규먼트, if any(있으면).  예를 들어, v-my-directive:foo 면 arg는 "foo"이다.
    • modifiers : modifier 를 담고 있는 객체. 예를 들어, v-my-directive.foo.bar면, modifiers object는 { foo: true, bar: true } 이다.
    • intance : 디렉티브가 사용되는 컴포넌트의 인스턴스.
    • dir : 지시어 정의 객체
  • vnode : 바인딩된 요소를 나타내는 기본 VNode
  • prevNode : 이전에 렌더링된 바운드 엘리먼트를 나타내는 VNode. 오직 beforeUpdate 와 updated 훅에서 가능하다.

예를 들면, 다음과 같은 지시어 사용을 고려하라 : 

<div v-example:foo.bar="baz">

binding 아규먼트는 다음과같은 모양의 객체가 될 수 있다:

{
  arg: 'foo',
  modifiers: { bar: true },
  value: // value of 'baz'
  oldValue : // 이전 업데이트에서 'baz'의 값
}

내재된 지시어와 비슷하게, 커스텀 지시어 아규먼트는 동적일 수 있다. 예를 들면:

<div v-example:[arg]="value"></div>

지시어 아규먼트가 우리 컴포넌트 상태에서 arg 프로퍼티를 기준으로 반응형으로 업데이트 될 것이다. 

Note
el과 달리, 이 규먼트들을 read-only로 다루고 절대 수정하지 마라. 훅사이에 정보를 공유할 필요가 있으면, e엘리먼트의 dataset을 사용하는걸 추천한다.

Function Shorthand

사용자 지정 지시어는 다른 훅 필요없이 mounted나 updated에 같을 동작을 하는 것이 일반적이다. 이런 케이스에서는 함수로 지시어를 정의할 수 있다:

<div v-color="color"></div>
app.directive('color', (el, binding) => {
  // 'mounted' 나 'updated' 둘다에서 호출된다 
  el.style.color = binding.value
})

 

Object Literals

지시어가 여러개의 값이 필요하면, 자바스크립트 객체 리터럴로 넘길 수 있다. 기억해라, 지시어들은 모든 유효한 자바스크립트 표현식을 받을 수 있다.

<div v-demo="{ color: 'white', text: 'hello!' }"></div>
app.directive('demo', (el, binding) => {
  console.log(binding.value.color) // => "white"
  console.log(binding.value.text) // => "hello!"
})

Usage on Components

컴포넌트들을 사용할 때, 커스텀 지시어는 Fallthrough Attributes와 비슷하게 컴포넌트의 루트 노드에 항상 적용된다.

<MyComponent v-demo="text" />
<!-- template of MyComponent -->

<div> <!-- v-demo directive will be applied here -->
  <span>My component content</span>
</div>

컴포넌트들이 하나의 루트 노드 이상을 가질 수 있다는 걸 기억해라. 멀티 루트 컴포넌트에 적용할 때, 지시어는 무시되고 워닝이 등장할 것이다. 어트리뷰트와 다르게, 지시어들은 v-bind="$attrs"로 다른 엘리먼트로 넘겨질 수 없다. 일반적으로, 컴포넌트들에 사용자 정의 지시어는 추천하지 않는다.

 

댓글