first commit
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
// v-reveal 디렉티브 — 요소가 뷰포트에 들어오면 등장 애니메이션 트리거
|
||||
// 사용법:
|
||||
// v-reveal → 기본(아래→위 fade-up)
|
||||
// v-reveal:scale → 확대 등장
|
||||
// v-reveal:fade → 투명도만
|
||||
// v-reveal="{ delay: 120 }" → 등장 지연(ms) — 스태거용
|
||||
// v-reveal:up="{ delay: i*90 }" → 타입 + 지연 조합
|
||||
//
|
||||
// 디렉티브는 서버/클라이언트 양쪽에 등록(미등록 시 SSR 렌더 크래시)하되,
|
||||
// IntersectionObserver 등 실제 동작은 클라이언트에서만 수행한다.
|
||||
// getSSRProps 를 제공해 SSR 단계에서 안전하게 통과시킨다.
|
||||
type RevealType = 'up' | 'scale' | 'fade'
|
||||
interface RevealValue {
|
||||
type?: RevealType
|
||||
delay?: number
|
||||
}
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
let observer: IntersectionObserver | null = null
|
||||
let reduceMotion = false
|
||||
|
||||
if (import.meta.client) {
|
||||
reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('is-revealed')
|
||||
observer?.unobserve(entry.target)
|
||||
}
|
||||
}
|
||||
},
|
||||
// 요소가 화면 하단에서 약간 올라온 시점에 트리거
|
||||
{ threshold: 0.15, rootMargin: '0px 0px -8% 0px' },
|
||||
)
|
||||
}
|
||||
|
||||
nuxtApp.vueApp.directive<HTMLElement, RevealValue | number | undefined>('reveal', {
|
||||
// SSR: 추가 속성 없이 통과 (디렉티브 미등록으로 인한 크래시 방지)
|
||||
getSSRProps: () => ({}),
|
||||
mounted(el, binding) {
|
||||
// 서버에서는 호출되지 않음. 모션 최소화 선호 시 애니메이션 없이 그대로 노출.
|
||||
if (reduceMotion || !observer) return
|
||||
|
||||
const value = binding.value
|
||||
const type: RevealType =
|
||||
(binding.arg as RevealType) ||
|
||||
(typeof value === 'object' && value?.type) ||
|
||||
'up'
|
||||
const delay = typeof value === 'number' ? value : value?.delay ?? 0
|
||||
|
||||
el.classList.add('reveal', `reveal-${type}`)
|
||||
if (delay) el.style.setProperty('--reveal-delay', `${delay}ms`)
|
||||
|
||||
observer.observe(el)
|
||||
},
|
||||
unmounted(el) {
|
||||
observer?.unobserve(el)
|
||||
},
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user