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>
:::
DropdownMenu 단독 사용
:::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>
:::
Dropdown 파라미터
| 파라미터 | 타입 | 기본값 | 설명 | 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 할지 여부 |
Dropdown 이벤트
| 이벤트명 | 콜백 파라미터 | 설명 | Demo 링크 |
|---|---|---|---|
| toggle | Function(status: boolean) |
컴포넌트 접힘/펼침 불리언 값. true는 펼칠 예정, false는 닫을 예정 | 트리거 방식 |
Dropdown 메서드
| 메서드명 | 타입 | 설명 |
|---|---|---|
| updatePosition | () => void |
dropdown 위치를 갱신하여 트리거 요소 옆에 따라가게 함 |
Dropdown 슬롯
| 슬롯명 | 설명 |
|---|---|
| default | 메뉴가 열릴 때의 트리거 요소 |
| menu | 드롭다운 메뉴 콘텐츠 |
DropdownMenu 파라미터
| 파라미터 | 타입 | 기본값 | 설명 |
|---|---|---|---|
| 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 스타일 커스텀 |
Dropdown 타입 정의
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를 단독으로 쓰면 원하는 요소에 자유롭게 드롭다운을 붙일 수 있어요.