v-if
, v-model
같은 Vue의 기본 디렉티브에 익숙합니다.
디렉티브는 v-
접두사가 붙은 특별한 속성으로, HTML 요소에 직접 추가하여 선언적인 방식으로 DOM을 조작하는 역할을 합니다.v-focus
라는 이름의 커스텀 디렉티브를 직접 만들어 보겠습니다.<script setup lang="ts">
import { onMounted, ref } from 'vue'
// 'vFocus'라는 이름으로 커스텀 디렉티브를 정의합니다.
// Vue는 카멜 케이스(vFocus)를 케밥 케이스(v-focus)로 자동 변환해 줍니다.
const vFocus = {
// 디렉티브가 바인딩된 요소가 DOM에 삽입되었을 때 호출됩니다.
mounted: (el: HTMLElement) => {
el.focus()
}
}
</script>
<template>
<!-- 이제 어떤 입력창이든 v-focus만 추가하면 자동으로 포커스됩니다. -->
<input v-focus placeholder="페이지 로드 시 포커스됩니다." />
</template>
vFocus
라는 객체를 만들고, mounted
라는 훅을 사용했습니다.
이 훅은 디렉티브가 적용된 <input>
요소가 실제 화면에 그려진 직후에 호출됩니다.
그리고 el
이라는 매개변수로 해당 요소를 직접 받아 el.focus()
를 실행하는 아주 간단한 원리입니다.use
로 시작합니다.useMouse
컴포저블을 직접 만들어 보겠습니다.
먼저, src/composables
라는 폴더를 새로 만들고, 그 안에 useMouse.ts
파일을 생성합니다.import { ref, onMounted, onUnmounted } from 'vue'
// 컴포저블 함수는 특별한 것이 아니라, 그냥 함수입니다.
export function useMouse() {
// 컴포저블 내부에서 상태를 관리합니다.
const x = ref(0)
const y = ref(0)
// 컴포저블 내부에서 생명주기 훅을 사용하여 이벤트를 관리할 수 있습니다.
function update(event: MouseEvent) {
x.value = event.pageX
y.value = event.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
// 관리하던 상태를 객체로 반환하여 외부 컴포넌트에서 사용할 수 있도록 합니다.
return { x, y }
}
useMouse
컴포저블을 어떤 컴포넌트에서든 아주 쉽게 가져와 사용할 수 있습니다.<script setup lang="ts">
// 우리가 만든 컴포저블을 임포트합니다.
import { useMouse } from '@/composables/useMouse'
// 함수를 호출하여 마우스 위치 상태를 가져옵니다.
const { x, y } = useMouse()
</script>
<template>
<div>
마우스 위치: {{ x }}, {{ y }}
</div>
</template>
useMouse
함수 안에 숨겨져 있습니다.
컴포넌트는 오직 x
와 y
라는 상태를 가져와 사용하기만 하면 됩니다.useMouse
함수는 이제 v-focus
처럼 명확한 DOM 관련 기능을 캡슐화하기에 좋습니다.다음 외전 2편에서는 컴포넌트를 더욱 유연하게 만들어주는Slot
과Teleport
에 대해 알아보겠습니다.