사용자 지정 디렉티브

시작

Vue는 코어에 포함된 기본 디렉티브 세트(v-modelv-show) 외에도 사용자 정의 디렉티브를 등록할 수 있습니다. Vue 2.0에서 코드 재사용 및 추상화의 기본 형식은 컴포넌트 입니다. 그러나 일반 엘리먼트에 하위 수준의 DOM 액세스가 필요한 경우가 있을 수 있으며 이 경우 사용자 지정 디렉티브가 여전히 유용할 수 있습니다. 다음은 input 엘리먼트와 focusing에 대한 예제입니다.

페이지가 로드되면 해당 엘리먼트는 포커스를 얻습니다. (참고: autofocus는 모바일 사파리에서 작동하지 않습니다.) 사실, 이 페이지를 방문한 이후 다른것을 클릭하지 않았다면 이 input 엘리먼트에 포커스가 되어 있어야 합니다.(참고: 모바일 사파리에서는 작동하지 않습니다.) 이제 이 작업을 수행하는 디렉티브를 작성하겠습니다.

// 전역 사용자 정의 디렉티브 v-focus 등록
Vue.directive('focus', {
  // 바인딩 된 엘리먼트가 DOM에 삽입되었을 때...
  inserted: function (el) {
    // 엘리먼트에 포커스를 줍니다
    el.focus()
  }
})

지시어를 로컬로 등록하기 위해서 컴포넌트는 directives 옵션을 허용합니다.

directives: {
  focus: {
    // 디렉티브 정의
    inserted: function (el) {
      el.focus()
    }
  }
}

그런 다음 템플릿에서 다음과 같이 모든 요소에서 새로운 v-focus 속성을 사용할 수 있습니다.

<input v-focus>

훅 함수

디렉티브 정의 객체는 여러가지 훅 함수를 제공할 수 있습니다.(모두 선택사항입니다.)

We’ll cover VNodes in more detail later, when we discuss render functions.

다음 섹션에서 이 훅으로 전달된 인자 (예: binding, vnodeoldVnode)를 살펴 보겠습니다.

디렉티브 훅 전달인자

디렉티브 훅은 다음을 전달인자로 사용할 수 있습니다.

el 뿐만아니라 모든 전달인자는 읽기 전용으로 사용하여야 합니다. 절대 변경하면 안됩니다. 훅을 통해 이 정보들을 전달하는 경우, 엘리먼트의 dataset을 이용하면 됩니다.

위 특성 중 일부를 사용하는 사용자 정의 디렉티브 예제입니다.

<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
Vue.directive('demo', {
  bind: function (el, binding, vnode) {
    var s = JSON.stringify
    el.innerHTML =
      'name: '       + s(binding.name) + '<br>' +
      'value: '      + s(binding.value) + '<br>' +
      'expression: ' + s(binding.expression) + '<br>' +
      'argument: '   + s(binding.arg) + '<br>' +
      'modifiers: '  + s(binding.modifiers) + '<br>' +
      'vnode keys: ' + Object.keys(vnode).join(', ')
  }
})

new Vue({
  el: '#hook-arguments-example',
  data: {
    message: 'hello!'
  }
})

다이나믹 디렉티브 전달인자

Directive arguments can be dynamic. For example, in v-mydirective:[argument]="value", the argument can be updated based on data properties in our component instance! This makes our custom directives flexible for use throughout our application.

Let’s say you want to make a custom directive that allows you to pin elements to your page using fixed positioning. We could create a custom directive where the value updates the vertical positioning in pixels, like this:

<div id="baseexample">
  <p>Scroll down the page</p>
  <p v-pin="200">Stick me 200px from the top of the page</p>
</div>
Vue.directive('pin', {
  bind: function (el, binding, vnode) {
    el.style.position = 'fixed'
    el.style.top = binding.value + 'px'
  }
})

new Vue({
  el: '#baseexample'
})

This would pin the element 200px from the top of the page. But what happens if we run into a scenario when we need to pin the element from the left, instead of the top? Here’s where a dynamic argument that can be updated per component instance comes in very handy:

<div id="dynamicexample">
  <h3>Scroll down inside this section ↓</h3>
  <p v-pin:[direction]="200">I am pinned onto the page at 200px to the left.</p>
</div>
Vue.directive('pin', {
  bind: function (el, binding, vnode) {
    el.style.position = 'fixed'
    var s = (binding.arg == 'left' ? 'left' : 'top')
    el.style[s] = binding.value + 'px'
  }
})

new Vue({
  el: '#dynamicexample',
  data: function () {
    return {
      direction: 'left'
    }
  }
})

Result:

Our custom directive is now flexible enough to support a few different use cases.

함수 약어

많은 경우에, bindupdate에서 같은 동작이 필요할 수 있습니다. 그러나 다른 훅은 신경 쓸 필요가 없습니다. 그 예로

Vue.directive('color-swatch', function (el, binding) {
  el.style.backgroundColor = binding.value
})

객체 리터럴

디렉티브에 여러 값이 필요한 경우, JavaScript 객체 리터럴을 전달할 수도 있습니다. 디렉티브는 유효한 JavaScript 표현식을 사용할 수 있습니다.

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