import { ref, onMounted, onUnmounted } from 'vue' /** * v-reveal 滚动入场指令 * * 用法: * v-reveal -> 默认向上淡入 * v-reveal="'left'" -> 从左侧滑入 * v-reveal="{ variant: 'scale', delay: 200 }" * * 支持的 variant: up | down | left | right | scale | blur */ const VARIANTS = { up: 'reveal-up', down: 'reveal-down', left: 'reveal-left', right: 'reveal-right', scale: 'reveal-scale', blur: 'reveal-blur', } function parseBinding(value) { if (!value) return { variant: 'up', delay: 0 } if (typeof value === 'string') return { variant: value, delay: 0 } return { variant: value.variant || 'up', delay: value.delay || 0, } } const reveal = { mounted(el, binding) { const { variant, delay } = parseBinding(binding.value) el.classList.add('reveal') el.classList.add(VARIANTS[variant] || 'reveal-up') if (delay) el.style.transitionDelay = `${delay}ms` // 已处于视口(如首屏)时立即显示,避免永远不可见 const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) { el.classList.add('reveal--in') observer.unobserve(el) } }, { threshold: 0.12, rootMargin: '0px 0px -8% 0px' } ) observer.observe(el) el.__revealObserver = observer }, unmounted(el) { if (el.__revealObserver) { el.__revealObserver.disconnect() delete el.__revealObserver } }, } export default reveal