아래와 같은 결과를 생성합니다:
라이브 미리보기
API
Popover
| 매개변수 | 설명 | 타입 | 기본값 |
|---|---|---|---|
| label | 팝오버의 제목 | string | slot | undefined |
| labelStyle | 제목 스타일 정의 | CSSProperties | {} |
| info | 팝오버 본문 내용 | string | slot | undefined |
| infoStyle | 본문 스타일 정의 | CSSProperties | {} |
| keyControl | 키보드 입력(enter 표시; esc 닫기) 지원 여부 |
boolean | true |
| popupStyle | 팝오버 전체 스타일 설정 | CSSProperties | {} |
추가적인 속성은 Tooltip 참조.
Slots
| 이름 | 설명 | 타입 |
|---|---|---|
| label | 사용자 정의 제목 | v-slot:label |
| info | 사용자 정의 본문 | v-slot:info |
| default | 기본 컨텐츠 | v-solt:default |
이벤트
| 이름 | 설명 | 타입 |
|---|---|---|
| visibilityChange | 보이거나 숨김 상태 변경 시 콜백 | (visible: boolean) => void |
팝오버 컴포넌트 만들기 Popover.vue
아래 도구 함수들을 사용합니다:
- useSlotCheck: 슬롯 존재 확인
- useAnimationFrame: requestAnimationFrame을 활용한 setTimeout 및 setInterval 대체
<script setup lang="ts">
import { computed } from 'vue'
import type { CSSProperties } from 'vue'
import Overlay from 'components/overlay'
import { useSlotCheck } from 'components/utils'
export interface PopoverProps {
label?: string // 제목
labelStyle?: CSSProperties // 제목 스타일
info?: string // 본문 내용
infoStyle?: CSSProperties // 본문 스타일
keyControl?: boolean // 키보드 조작 가능 여부
popupStyle?: CSSProperties // 팝오버 스타일
}
const props = withDefaults(defineProps<PopoverProps>(), {
label: undefined,
labelStyle: () => ({}),
info: undefined,
infoStyle: () => ({}),
keyControl: true,
popupStyle: () => ({})
})
const slotCheck = useSlotCheck(['label', 'info'])
const hasLabel = computed(() => slotCheck.label || props.label)
const hasInfo = computed(() => slotCheck.info || props.info)
</script>
<template>
<Overlay
max-width="auto"
bg-color="#fff"
:popup-style="{
padding: '12px',
borderRadius: '8px',
textAlign: 'start',
...popupStyle
}"
:key-control="keyControl"
:transition-duration="200"
>
<template #content>
<div v-if="hasLabel" class="popover-label" :class="{ mb8: hasInfo }" :style="labelStyle">
<slot name="label">{{ label }}</slot>
</div>
<div v-if="hasInfo" class="popover-info" :style="infoStyle">
<slot name="info">{{ info }}</slot>
</div>
</template>
<slot></slot>
</Overlay>
</template>
<style lang="less" scoped>
.popover-label {
min-width: 176px;
color: rgba(0, 0, 0, 0.88);
font-weight: 600;
}
.mb8 {
margin-bottom: 8px;
}
.popover-info {
color: rgba(0, 0, 0, 0.88);
}
</style>
페이지에서 컴포넌트 사용하기
다음과 같은 구성 요소들이 필요합니다:
- Vue3 버튼(Button)
- Vue3 간격(Space)
<script setup lang="ts">
import Popover from './Popover.vue'
import { ref } from 'vue'
const visible = ref(false)
function onVisibilityChange(visible: boolean) {
console.log('visible', visible)
}
</script>
<template>
<div class="ml60">
<h1>{{ $route.name }} {{ $route.meta.title }}</h1>
<h2 class="mt30 mb10">기본 사용법</h2>
<Popover label="제목" @visibility-change="onVisibilityChange">
<template #info>
<p>내용</p>
<p>내용</p>
</template>
<Button type="primary">마우스오버</Button>
</Popover>
<h2 class="mt30 mb10">사용자 정의 스타일</h2>
<Popover
:max-width="180"
bg-color="#000"
:label-style="{ fontSize: '16px', fontWeight: 'bold', color: '#1677ff' }"
:info-style="{ color: '#fff' }"
:popup-style="{ padding: '12px 18px', borderRadius: '12px' }"
>
<template #label> 사용자 정의 제목 </template>
<template #info>
<p>사용자 정의 내용</p>
<p>사용자 정의 내용</p>
</template>
<Button type="primary">마우스오버</Button>
</Popover>
<h2 class="mt30 mb10">다양한 트리거 방식</h2>
<Space>
<Popover label="호버 제목">
<template #info>
<p>내용</p>
<p>내용</p>
</template>
<Button type="primary">호버</Button>
</Popover>
<Popover label="클릭 제목" trigger="click">
<template #info>
<p>내용</p>
<p>내용</p>
</template>
<Button type="primary">클릭</Button>
</Popover>
</Space>
<h2 class="mt30 mb10">팝업 내에서 닫기</h2>
<h3 class="mb10">show 속성을 통해 표시/숨김 제어</h3>
<Popover v-model:visible="visible" label="클릭 제목" trigger="click">
<template #info>
<a @click="visible = false">닫기</a>
</template>
<Button type="primary">클릭</Button>
</Popover>
<h2 class="mt30 mb10">사용자 정의 전환 시간</h2>
<Popover label="전환 시간 300ms" :transition-duration="300">
<template #info>
<p>내용</p>
<p>내용</p>
</template>
<Button type="primary">전환 시간 300ms</Button>
</Popover>
<h2 class="mt30 mb10">지연 표시/숨김</h2>
<Space>
<Popover :show-delay="300" :hide-delay="300" label="지연 300ms" info="Vue Amazing UI">
<Button type="primary">지연 300ms 팝오버</Button>
</Popover>
<Popover :show-delay="500" :hide-delay="500" label="지연 500ms" info="Vue Amazing UI">
<Button type="primary">지연 500ms 팝오버</Button>
</Popover>
</Space>
<h2 class="mt30 mb10">화살표 숨기기</h2>
<Popover :arrow="false" label="제목">
<template #info>
<p>내용</p>
<p>내용</p>
</template>
<Button type="primary">화살표 숨기기</Button>
</Popover>
</div>
</template>