본문 바로가기
front/vue

[Vue] Custom Directives

by juniKang 2022. 7. 29.

Introduction

v-model 이나 v-show같은 코어에 있는 지시어에 더해서, 뷰는 커스텀 지시어를 등록하는 기능을 제공한다.

 

뷰의 코드 재사용의 두가지 폼인 컴포넌트와 composables를 소개했다. 컴포넌트들은 설계의 주요 부품인 반면에, composables는 상태를 가지고 있는 로직의 재사용에 중점을 뒀다. 커스텀 지시어들은 반면에, 순수한 엘리먼트에 접근하는 로우레벨의 DOM과 연관된 재사용 가능한 로직을 다루는 것에 중점을 뒀다.

 

컴포넌트와 유사하게  커스텀 지시어들은 라이프사이클 훅을 담고있는 오브젝트로 정의된다. 훅들은 지시어가 바운드된 엘리먼트를 받는다. 다음은 뷰에의해 엘리먼트가 돔으로 삽입되었을 때 인풋을 포커싱 해주는 지시어의 예제이다.

<script setup>
// enables v-focus in templates
const vFocus = {
  mounted: (el) => el.focus()
}
</script>

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

 

페이지의 어떤곳도 클릭하지 않았다고 가정했을 때, 위의 인풋은 자동으로 포커싱 될 것이다.  이 지시어는 autofocus 애트리뷰트보다 좀 더 유용한데, 왜냐하면, 페이지가 로드되었을 때 뿐만아니라, 뷰에의해 동적으로 엘리먼트를 삽입했을 때에도 동작하기 때문이다.

 

<script setup>에서는 v로 시작하는 camelCase 변수들은 모두 커스텀 지시어로서 간주된다. 위에 예를 보면, vFocus는 템플릿에서 v-focus로 사용됐다.

 

<script seupt>을 사용하지 않으면, 커스텀 지시어는 directives 옵션에의해 등록된다. 

export defualt {
  setup() {
    /*...*/
  },
  directives: {
    // enables v-focus in template
    focus: {
      /* ... */
    }
  }
}

앱 레벨로 전역적으로 커스텀 지시어를 등록하는 것도 흔하다.

const app = createApp({})

// make v-focus usable in all components
app.directive('focus'), {
  /* ... */
})

팁 : 커스텀 지시어들은 직접적인 돔 조작을 이루기 위한 함수적인 열망일 때만 사용해야 한다. 가능한한 v-bind처럼 내장된 지시어를 사용해서 선언적인 템플릿입력을 선호하라. 왜냐하면, 그것들이 좀더 효율적이고 서버렌더링에 친근하기 때문이다.

 

Directive Hooks

지시어 정의 객체는 여러가지 훅 함수들을 제공할 수 있다. (all optional):

  • created(el, binding, vnode, prevVnode) {}
    엘리먼트의 애트리뷰트가 바운드되기 전에 호출되거나, 이벤트 리스너가 적용되었을 때 호출
  • beforeMount(el, binding, vnode, prevVnode) {}
    엘리먼트가 돔에 삽입되기 직전에 호출
  • mounted(el, binding, vnode, prevVnode) {}
    바운드된 엘리먼트의 부모 컴포넌트와 그 엘리먼트의 모든 칠드런들이 마운트 되었을 때 호출
  • beforeUpdate(el, binding, vnode, prevVnode) {}
    부모 컴포넌트가 업데이트되기 전에 호출
  • updated(el, binding, vnode, prevVnode) {}
    부모 컴포넌트와 모든 그 자식들이 업데이트 되었을 때 호출
  • beforeUnmount(el, binding, vnode, prevVnode) {}
    부모 컴포넌트가 언마운트 되기 전에 호출
  • unmounted(el, binding, vnode, prevVnode) {}
    부모 컴포넌트가 언마운트 되기 전에 호출

Hook Arguments

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

  • el : 지시어가 바운드되는 엘리먼트. 이것은 돔을 직접 조작할 때 사용된다.
  • binding : 아래 프로퍼티들을 담고있는 객체
    • value : 지시어로 전달되는 값. 예를들면, v-my-directive="1 + 1", 의 value는 2 이다.
    • oldValue : 이전 값, 오직 beforeUpdate 와 updated 에서만 가능하다. 이건 value가 변경되었는지 아닌지에 따라 사용가능하다.
    • arg : 지시어로 전달되는 아규먼트가 있으면 사용한다. 예를 들면, v-my-directive:foo,는 arg에는 "foo" 가 들어간다.
    • modifiers : 지시어로 전달되는 modifier가 있으면 사용한다. 예를들어, v-my-directive.foo.bar에서, modifier는 { foo: true, bar: true } 이다.
    • instance : 지시어가 사용되는 컴포넌트의 인스턴스 이다.
    • dir : 지시어 정의 객체이다. 
  • vnode : 바인딩된 에릴먼트를 나타내는 기본적인 VNode이다.
  • prevVNode: 이전에 렌더로 부터 바운드된 엘리먼트를 나타내는 VNode. 오직 beforeUpdate나 updated 훅에서 사용가능하다.

예를 들면, 아래 지시어 사용을 보자:

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

binding 아규먼트는 다음과 같은 모양의 객체일 것이다: 

{
  arg: 'foo',
  modifiers: { bar: true },
  value: /* value of `baz` */,
  oldValue: /* value of `baz` from previous update */
}

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

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

여기 지시어 아규먼트는 우리의 컴포넌트 상태에서 arg 프로퍼티에 기반을 두고 반응형으로 업데이트 될 수 있다.

 

Note: el과 달리, 이 아규먼트들은 read-onlu로서 절대로 수정하지 말아야 한다. 만약 훅간에 정보들을 공유해야 한다면, 엘리먼트의 dataset을 통해 하는 것을 추천한다.

 

Function Shorthang

다른 훅의 도움 없이, mounted와 updated가 같은 동작을 하는 것은 커스텀 지시어에서 흔하다. 이런 케이스에서 우리는 directive 함수로 정의할 수 있다.

<div v-color="color"></div>
app.directive('color', (el, binding) => {
  // this will be called for both `mounted` and `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="test" />
<!-- template of MyComponent -->

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

컴포넌트들은 잠재적으로 하나 이상의 루트노드를 가질 수 있음을 주의하라. 여러개의 루트를 가진 컴포넌트에 적용될 떄, 지시어는 무시되고, 워닝이 나올 것이다. 어트리뷰트와 달리, 지시어들은 v-bind="$attrs"로 다른 엘리먼트들로 넘겨질 수 없다. 일반적으로, 지시어를 컴포넌트에 사용하는 것은 추천하지 않는다.

'front > vue' 카테고리의 다른 글

[Vue] h()  (1) 2022.07.30
[Vue] defineComponent()  (0) 2022.07.30
[vue3] checkbox specification  (2) 2022.07.25
[eslint] vue3 eslint 설정  (0) 2022.07.23
순수자바스크립트로 뷰의 반응형 구현하기(ref, watchEffect, computed)  (0) 2022.07.12

댓글