본문 바로가기

Frontend Development/Vue.js

[Vue.js] 사용자 정의 directive (custom directive)

사용자 정의 리렉티브란

 

Vue 에서는 v-if, v-for, v-on, v-model등 다양한 디렉티브를 사용한다. 디렉티브가 하는 일을 프로그램의 관점에서 생각해 보면, 내부적으로 주어진 데이터에 따라 DOM을 조작하는 역할을 한다. 예를 들어 v-show는 값이 참이냐 거짓이냐에 따라 DOM 요소의 스타일에 display 프로퍼티 값을 수정한다.

 

그러나 때에 따라서는 Vue.js 내장 디렉티브 만으로는 구현할 수 없는 깊숙한 곳에 있는 요소에 대한 DOM 조작을 공통화 하고 싶다던가 DOM API를 호출하는 라이브러리를 Vue.js 애플리케이션에서 재사용 가능한 형태로 포함시키고 싶은 경우가 있다.

 

사용자 정의 디렉티브는 DOM 요소에 대한 저수준(low-level) 접근을 제공한다. 바꿔 말하면 DOC 요소를 조작해 동작을 원하는 대로 수정하거나 새로운 기능을 추가할 수 있게 해준다.

 

사용자 정의 디렉티브 정의하기

 

img 요소를 확장해서 이미지의 URL이 유효하지 않은 경우 대체 이미지로 폴백(fall-back)하는 디렉티브인 v-img-fallback을 만들어보자. HTML의 img요소에 이 사용자 정의 디렉티브를 적용해서 이미지를 받아오지 못한 경우의 로직을 추가한다.

 

index.html

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vue app</title>
    <script src="https://unpkg.com/vue@2.5.17"></script>
    <script src="app.js"></script>
</head>

<body>
    <div id="app">
        <!-- src 속성값은 아까와 마찬가지로 존재하지 않는 URL이다 -->
        <img v-fallback-image src="./logo.png" :alt="altText">
    </div>
    <script src="./app.js"></script>
</body>

</html>

 

app.js

Vue.directive('fallback-image', {
  bind: function (el, binding) {
    console.log('bind', binding)
    el.addEventListener('error', function () {
      el.src = 'https://dummyimage.com/400x400/000/ffffff.png&text=no+image'
    })
  },
  update: function (el, binding) {
    console.log('update', binding)
  }
})

var vm = new Vue({
  el: '#app',
  data: function () {
    return {
      altText: 'logo'
    }
  }
})

 

테스트 결과

 

위 소스들과 같은 폴더에 logo.png파일을 두고 브라우저로 index.html을 실행하면 img 랜더링이 정상적으로 되어서 logo.png파일이 화면에 출력된다.

 

여기서 logo.png의 이름을 다른 이름으로 바꾸고 index.html을 실행해보면 img 태그 렌더링시 error가 발생하고 걸어 두었던 v-fallback-image 디렉티브에 지정한 bind 함수에 의해 실패 시 지정한 이미지가 출력되게 된다.

 

스크립트 내용

 

전역 디렉티브를 등록하려면 Vue.directive라는 API를 사용한다. 이 API의 첫번째 인자는 디렉티브의 이름이고, 두 번째 인자는 동작을 정의하는 디렉티브 정의 객체다.

 

Vue.directive('fallback-image', 

// 두 번째 인자는 동작을 정의하는 디렉티브 정의 객체. 아래는 bind, update 훅 함수에 대한 정의가 되어 있다.
{
  bind: function (el, binding) {
    console.log('bind', binding)
    el.addEventListener('error', function () {
      el.src = 'https://dummyimage.com/400x400/000/ffffff.png&text=no+image'
    })
  },
  update: function (el, binding) {
    console.log('update', binding)
  }
}

)
훅이름 내용
bind 디렉티브가 대상 요소와 연결됬을 때 단 한 번 호출됨.
inserted 연결된 요소가 부모 요소에 삽입되는 시점에 호출됨(부모 요소의 존재는 보장되나, 요소가 문서에 포함되는지는 보장되지 않음)
update 디렉티브 값의 변화 등에 따라 연결된 요소를 포함하는 컴포넌트의 VNode가 수정될 때 호출됨. 디렉티브 값이 변화하지 않아도 호출될 수 있으므로 값의 이전값과 비교해 불필요한 호출을 방지한다.
componentUpdated 컴포넌트의 VNode와 자식 컴포넌트의 VNode가 수정됬을 때 호출됨.
unbind 디렉티브가 연결된 요소와 분리됬을 때 단 한 번 호출됨. bind로 등록한 이벤트 리스너 삭제 등 뒷정리를 목적으로 사용한다.