본문으로 바로가기 본문 바로가기
WIKI 기술 지식 베이스

Dropdown 드롭다운 메뉴

원문 보기 위키 갱신

눌렀을 때 목록이 펼쳐지는 컴포넌트예요.

출처: 문서

본문

언제 사용하나요

화면의 조작 명령이 너무 많을 때, 이 컴포넌트로 조작 요소를 정리할 수 있어요. 트리거 지점을 클릭하거나 마우스를 올리면 드롭다운 메뉴가 나타나고, 목록에서 항목을 선택해 해당 명령을 실행할 수 있어요.

기본 사용법

:::demo 컴포넌트 기본 슬롯에 트리거 요소를 정의하고, menu 슬롯에 메뉴를 정의해요. 기본적으로 트리거 요소를 클릭하면 메뉴가 펼쳐져요.

<template>
  <d-dropdown style="width: 100px;" :position="position">
    <d-button>Click Me</d-button>
    <template #menu>
      <ul class="list-menu">
        <li class="menu-item">Item 1</li>
        <li class="menu-item">Item 2</li>
        <li class="menu-item">Item 3</li>
        <li class="menu-item">Item 4</li>
      </ul>
    </template>
  </d-dropdown>
</template>

<script>
import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    return {
      position: ref(['bottom-start', 'right', 'top-end']),
    };
  },
});
</script>

<style>
.list-menu {
  padding: 0;
  margin: 0;
  width: 100px;
}
.menu-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100px;
  padding: 4px;
  cursor: pointer;
}
.menu-item:hover {
  background-color: var(--devui-list-item-hover-bg, #f2f5fc);
  color: var(--devui-list-item-hover-text, #526ecc);
}
</style>

:::

트리거 방식

:::demo 컴포넌트는 기본적으로 click 방식으로 펼쳐져요. hover 방식은 마우스를 트리거 요소 위에 올리면 메뉴가 펼쳐지고, manually 방식은 수동 제어로 visible 설정으로 컴포넌트의 펼침 여부를 제어해요.

<template>
  <div class="space-y-s">
    <div class="flex items-center">
      触发方式:
      <d-radio-group direction="row" v-model="trigger">
        <d-radio v-for="item in triggerList" :key="item" :value="item">{{ item }}</d-radio>
      </d-radio-group>
    </div>
  </div>
  <d-dropdown :visible="isOpen" :trigger="trigger" :position="position" @toggle="handleToggle">
    <d-button class="mt-1">More</d-button>
    <template #menu>
      <ul class="list-menu">
        <li class="menu-item">Item 1</li>
        <li class="menu-item">Item 2</li>
        <li class="menu-item">Item 3</li>
        <li class="menu-item">Item 4</li>
      </ul>
    </template>
  </d-dropdown>
  <d-button v-show="trigger === 'manually'" @click="isOpen = !isOpen" style="margin-left: 8px;">
    {{ !isOpen ? 'show dropdown' : 'close dropdown' }}
  </d-button>
</template>

<script>
import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    return {
      isOpen: ref(false),
      trigger: ref('click'),
      triggerList: ['click', 'hover', 'manually'],
      position: ref(['bottom-start']),
      handleToggle: (val) => {
        console.log(val);
      },
    };
  },
});
</script>

:::

닫기 영역 설정

:::demo close-scope 파라미터로 클릭 닫기 영역을 설정해요. 기본값은 all로 메뉴 내부와 외부를 클릭하면 모두 닫히고, blank는 메뉴가 아닌 빈 공간을 클릭할 때만 닫히며, none은 내부와 외부 모두 닫지 않고 드롭다운 버튼으로만 닫을 수 있어요.

<template>
  <div class="space-y-s">
    <div class="flex items-center">
      关闭区域:
      <d-radio-group direction="row" v-model="closeScope">
        <d-radio v-for="item in closeScopeAreas" :key="item" :value="item">{{ item }}</d-radio>
      </d-radio-group>
    </div>
  </div>
  <d-dropdown :close-scope="closeScope" :position="position" style="width: 100px;">
    <d-button class="mt-1">More</d-button>
    <template #menu>
      <ul class="list-menu">
        <li class="menu-item">Item 1</li>
        <li class="menu-item">Item 2</li>
        <li class="menu-item">Item 3</li>
        <li class="menu-item">Item 4</li>
      </ul>
    </template>
  </d-dropdown>
</template>

<script>
import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    return {
      closeScope: ref('all'),
      closeScopeAreas: ['all', 'blank', 'none'],
      position: ref(['bottom-start']),
    };
  },
});
</script>

:::

다단 메뉴

:::demo

<template>
  <d-dropdown>
    <d-button>Click Me</d-button>
    <template #menu>
      <ul class="list-menu">
        <d-dropdown :position="position" :offset="0">
          <li class="menu-item">
            Item 1
            <i class="icon icon-chevron-right"></i>
          </li>
          <template #menu>
            <ul class="list-menu">
              <d-dropdown :position="position" :offset="0">
                <li class="menu-item">
                  Item 1-1
                  <i class="icon icon-chevron-right"></i>
                </li>
                <template #menu>
                  <ul class="list-menu">
                    <li class="menu-item">Item 1-1-1</li>
                    <li class="menu-item">Item 1-1-2</li>
                    <li class="menu-item">Item 1-1-3</li>
                  </ul>
                </template>
              </d-dropdown>
              <li class="menu-item">Item 1-2</li>
            </ul>
          </template>
        </d-dropdown>
        <li class="menu-item">Item 2</li>
      </ul>
    </template>
  </d-dropdown>
</template>

<script>
import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    return {
      position: ref(['right-start', 'right-end']),
    };
  },
});
</script>

:::

:::demo

<template>
  <d-button ref="origin" @click="isOpen = !isOpen">More</d-button>
  <d-dropdown-menu v-model="isOpen" :origin="origin?.$el">
    <d-list style="width: 100px;">
      <d-list-item v-for="item of data" :key="item.value" @click="change(item.value)">{{ item.label }}</d-list-item>
    </d-list>
  </d-dropdown-menu>
</template>

<script>
import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    const isOpen = ref(false);
    const origin = ref(null);
    const data = [
      { value: 'item 1', label: 'Item 1' },
      { value: 'item 2', label: 'Item 2' },
      { value: 'item 3', label: 'Item 3' },
    ];
    const change = (value) => {
      console.log('value', value);
      isOpen.value = false;
    };

    return {
      isOpen,
      origin,
      data,
      change,
    };
  },
});
</script>

:::

파라미터 타입 기본값 설명 Demo 링크
visible boolean false 선택, dropdown 열림 여부 명시적 지정 트리거 방식
trigger TriggerType click 선택, dropdown 트리거 방식. click은 클릭, hover는 호버, manually는 완전 수동 제어 트리거 방식
close-scope CloseScopeArea all 선택, 클릭 닫기 영역. blank는 메뉴 외부 빈 곳 클릭 시 닫기, all은 메뉴 내외부 클릭 시 닫기, none은 트리거 요소만 닫기 닫기 가능 영역
position Placement[] ['bottom'] 선택, 펼침 위치. 순서대로 자동 선택 기본 사용법
offset number | OffsetOptions 4 선택, 트리거 요소와의 간격 지정 다단 메뉴
shift-offset number -- 선택, 설정 시 엣지 붙이기 기능 활성화. 지정한 position이 들어가지 않으면 가장 가까운 뷰 경계에 정렬하며, 이 파라미터로 뷰 경계 기준 오프셋 설정 가능
close-on-mouse-leave-menu boolean false 선택, 메뉴에 진입 후 떠날 때 메뉴 닫기 여부
show-animation boolean true 선택, 애니메이션 표시 제어
overlay-class string -- 선택, overlay 스타일 커스텀
destroy-on-hide boolean true 선택, dropdown 닫을 때 파괴 여부
teleport string | HTMLElement 'body' 선택, 마운트 노드. Teleport 컴포넌트의 to 속성과 동일
append-to-body boolean true 선택, 드롭다운 메뉴를 body에 append 할지 여부
이벤트명 콜백 파라미터 설명 Demo 링크
toggle Function(status: boolean) 컴포넌트 접힘/펼침 불리언 값. true는 펼칠 예정, false는 닫을 예정 트리거 방식
메서드명 타입 설명
updatePosition () => void dropdown 위치를 갱신하여 트리거 요소 옆에 따라가게 함
슬롯명 설명
default 메뉴가 열릴 때의 트리거 요소
menu 드롭다운 메뉴 콘텐츠
파라미터 타입 기본값 설명
origin HTMLElement -- 필수, DropdownMenu의 연관 요소를 반드시 지정
v-model boolean false 필수, DropdownMenu 열림 여부 지정
position Placement[] ['bottom'] 선택, 펼침 위치. 위치에 start 또는 end가 포함되면 align 파라미터로 정렬 방식 설정 필요
align start | end | null null 선택, 정렬 방식. 기본은 가운데 정렬. start 정렬 지정 시 start 위치에 들어가지 않으면 자동으로 end 정렬로 조정
offset number | OffsetOptions 4 선택, 트리거 요소와의 간격 지정
close-outside () => boolean () => true 선택, 외부 영역 클릭 콜백 함수. 기본값은 true를 반환하며, 외부 영역 클릭 시 DropdownMenu가 닫힘
show-animation boolean true 선택, 애니메이션 표시 제어
overlay-class string -- 선택, overlay 스타일 커스텀

TriggerType

type TriggerType = 'click' | 'hover' | 'manually';

CloseScopeArea

type CloseScopeArea = 'all' | 'blank' | 'none';

Placement

type Placement =
  | 'top'
  | 'right'
  | 'bottom'
  | 'left'
  | 'top-start'
  | 'top-end'
  | 'right-start'
  | 'right-end'
  | 'bottom-start'
  | 'bottom-end'
  | 'left-start'
  | 'left-end';

OffsetOptions

type OffsetOptions = { mainAxis?: number; crossAxis?: number };

더 알아보기 (Learn more)

trigger로 클릭·호버·수동 트리거 방식을 고르고, close-scope로 닫기 영역을 제어하며, position 배열 순서대로 자동 배치까지 해줘요. d-dropdown-menu를 단독으로 쓰면 원하는 요소에 자유롭게 드롭다운을 붙일 수 있어요.