Skip to content

v-z-index 디렉티브

v-z-index는 오버레이 컴포넌트(모달, 다이얼로그, 툴팁 등)의 z-index 값을 일관되고 체계적으로 관리할 수 있도록 설계된 Vue 디렉티브입니다. 이 디렉티브는 미리 정의된 z-index 맵을 사용하여 엘리먼트의 z-index 값을 설정합니다.

기본 사용법

v-z-index 디렉티브는 z-index 맵에 정의된 키 값을 받아 해당하는 z-index 값을 엘리먼트에 적용합니다.

vue
<template>
    <div v-z-index="BASE_Z_INDEX_KEY.MODAL">
        <!-- 모달 내용 -->
    </div>
</template>

<script setup lang="ts">
import { BASE_Z_INDEX_KEY } from '@jennifersoft/vue-components-v2';
</script>

z-index 맵 구성하기

애플리케이션에서 사용할 z-index 맵은 다음과 같이 구성할 수 있습니다:

typescript
// zIndex.config.ts
import {
    createZIndexMap,
    BASE_Z_INDEX_KEY,
} from '@jennifersoft/vue-components-v2';

export const Z_INDEX_KEY = {
    LICENSE: 'license',
    ...BASE_Z_INDEX_KEY, // 기본 제공되는 키 값 (TOOLTIP, MENU, DIALOG, MODAL, DRAWER)
    POPUP: 'popup',
    NAVIGATION_BAR: 'navigationBar',
    NAVIGATION_PANEL: 'navigationPanel',
} as const;
export type ZIndexMap = (typeof Z_INDEX_KEY)[keyof typeof Z_INDEX_KEY];

export const zIndexMap = createZIndexMap(Z_INDEX_KEY);

전역 등록

v-z-index 디렉티브를 애플리케이션 전역에서 사용하려면 다음과 같이 등록합니다:

typescript
// index.ts 또는 main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { createZIndexDirective } from '@jennifersoft/vue-components-v2';
import { zIndexMap } from '@container/layer/zIndex.config';

const app = createApp(App);
app.directive('z-index', createZIndexDirective(zIndexMap));
app.mount('#app');

API

디렉티브 값 (binding.value)

v-z-index 디렉티브는 다음과 같은 값을 받을 수 있습니다:

타입설명
stringz-index 맵에 정의된 키 값

createZIndexDirective 함수

매개변수타입설명
zMapBaseZIndexMapz-index 값이 정의된 맵 객체

createZIndexMap 함수

매개변수타입설명
keyMapRecord<string, string>z-index 키가 정의된 객체

작동 방식

  1. createZIndexMap 함수는 키 맵을 받아 각 키에 대한 z-index 값을 계산합니다.
  2. 키 맵의 순서에 따라 z-index 값이 할당되며, 객체에서 위에 정의된 키일수록 더 높은 z-index 값을 가집니다.
  3. 기본 z-index 값은 10000부터 시작하여 각 키마다 1000씩 증가합니다.
  4. createZIndexDirective 함수는 z-index 맵을 받아 Vue 디렉티브를 생성합니다.
  5. 디렉티브가 적용된 엘리먼트는 마운트 및 업데이트 시 해당하는 z-index 값이 style 속성으로 설정됩니다.

실제 사용 예시

DRAWER
DIALOG
TOOLTIP
vue
<template>
    <!-- BASE_Z_INDEX_KEY의 각 키를 사용한 예시 -->
    <div class="z-index-demo">
        <div v-z-index="BASE_Z_INDEX_KEY.DRAWER" class="z-index-box drawer">
            DRAWER
        </div>
        <div v-z-index="BASE_Z_INDEX_KEY.MODAL" class="z-index-box modal">
            MODAL
        </div>
        <div v-z-index="BASE_Z_INDEX_KEY.DIALOG" class="z-index-box dialog">
            DIALOG
        </div>
        <div v-z-index="BASE_Z_INDEX_KEY.MENU" class="z-index-box menu">
            MENU
        </div>
        <div v-z-index="BASE_Z_INDEX_KEY.TOOLTIP" class="z-index-box tooltip">
            TOOLTIP
        </div>
    </div>
</template>

<script setup lang="ts">
import { BASE_Z_INDEX_KEY } from '@jennifersoft/vue-components-v2';
</script>

<style>
.z-index-demo {
    display: flex;
    justify-content: center;
    align-items: center;
    position: relative;
    width: 100%;
    height: 300px;
    margin: 20px 0;
}

.z-index-box {
    position: absolute;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 120px;
    height: 80px;
    border: 2px solid #333;
    font-weight: bold;
    color: white;
}

.drawer {
    background-color: var(--gray-600);
    left: 80px;
    top: 20px;
}

.modal {
    background-color: var(--gray-500);
    left: 160px;
    top: 40px;
}

.dialog {
    background-color: var(--gray-400);
    left: 240px;
    top: 60px;
}

.menu {
    background-color: var(--gray-300);
    left: 320px;
    top: 80px;
}

.tooltip {
    background-color: var(--gray-200);
    left: 400px;
    top: 100px;
}
</style>

디렉티브 중첩 사용

v-z-index가 이미 내부에 적용된 컴포넌트에 외부에서 다시 v-z-index를 적용하면 외부에서 적용한 값이 우선합니다. 이를 활용하면 기존 컴포넌트의 z-index 값을 재정의할 수 있습니다.

예를 들어, OverlayMask 컴포넌트는 내부적으로 이미 v-z-index="BASE_Z_INDEX_KEY.MASK"가 적용되어 있지만, 외부에서 다른 z-index 값을 적용하면 외부 값이 우선합니다.

기본 OverlayMask (MASK z-index)
재정의된 OverlayMask (DIALOG z-index)
vue
<template>
    <div class="example-container">
        <OverlayMask class="mask-default">
            기본 OverlayMask (MASK z-index)
        </OverlayMask>

        <OverlayMask
            v-z-index="BASE_Z_INDEX_KEY.DIALOG"
            class="mask-overridden"
        >
            재정의된 OverlayMask (DIALOG z-index)
        </OverlayMask>
    </div>
</template>

<script setup lang="ts">
import { OverlayMask, BASE_Z_INDEX_KEY } from '@jennifersoft/vue-components-v2';
</script>

<style scoped>
.example-container {
    position: relative;
    height: 200px;
    width: 100%;
}

.mask-default,
.mask-overridden {
    position: absolute;
    color: white;
    font-weight: bold;
    border: 2px solid #333;
    white-space: nowrap;
}

.mask-default {
    background-color: rgba(0, 0, 0, 0.7);
    left: 50px;
    top: 30px;
}

.mask-overridden {
    background-color: rgba(46, 139, 87, 0.8);
    left: 150px;
    top: 70px;
}
</style>

이 예제에서:

  1. 첫 번째 OverlayMask는 내부적으로 적용된 BASE_Z_INDEX_KEY.MASK 값을 사용합니다 (z-index: 10000).
  2. 두 번째 OverlayMask는 외부에서 BASE_Z_INDEX_KEY.DIALOG 값을 적용하여 내부 값을 재정의합니다 (z-index: 13000).

이런 방식은 다음과 같은 상황에서 유용합니다:

  1. 기존 컴포넌트 라이브러리의 컴포넌트를 사용하면서 z-index를 재정의해야 하는 경우
  2. 동적으로 컴포넌트의 중첩 순서를 변경해야 하는 경우
  3. 특정 화면에서만 컴포넌트의 z-index 값을 일시적으로 변경해야 하는 경우

유의사항

  1. v-z-index 디렉티브를 사용하기 전에 반드시 z-index 맵을 구성하고 디렉티브를 최상위 파일에 등록해야 합니다.
  2. 최상위 파일에 등록하더라도, 파일에서 직접 vZIndex.ts를 import 하면 기본 z-index 값만 적용됩니다.
  3. 존재하지 않는 키 값을 사용하면 콘솔에 경고 메시지가 출력되고 z-index가 적용되지 않습니다.
  4. z-index 맵의 키 순서는 중요합니다. 객체에서 위에 정의된 키일수록 더 높은 z-index 값을 가집니다.
  5. 컴포넌트에 이미 v-z-index가 적용되어 있는 경우, 외부에서 다시 v-z-index를 적용하면 외부 값이 우선합니다.