Files
hunli/vite-tailwindcss/src/directives/reveal.js
2026-08-12 13:52:54 +08:00

87 lines
2.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* v-reveal 滚动入场指令
*
* 用法:
* v-reveal -> 默认向上淡入
* v-reveal="'left'" -> 从左侧滑入
* v-reveal="{ variant: 'scale', delay: 200 }"
* v-reveal="{ variant: 'up', immediate: true }" -> 不建观察器,下一帧直接入场(串行挂载用)
*
* 支持的 variant: up | down | left | right | scale | blur | postcard
*/
const VARIANTS = {
up: 'reveal-up',
down: 'reveal-down',
left: 'reveal-left',
right: 'reveal-right',
scale: 'reveal-scale',
blur: 'reveal-blur',
postcard: 'reveal-postcard',
}
function parseBinding(value) {
if (!value) return { variant: 'up', delay: 0, immediate: false }
if (typeof value === 'string') return { variant: value, delay: 0, immediate: false }
return {
variant: value.variant || 'up',
delay: value.delay || 0,
immediate: !!value.immediate,
}
}
const reveal = {
mounted(el, binding) {
// false跳过入场同模板不挂观察器
if (binding.value === false) return
const { variant, delay, immediate } = parseBinding(binding.value)
el.classList.add('reveal')
el.classList.add(VARIANTS[variant] || 'reveal-up')
if (delay) el.style.transitionDelay = `${delay}ms`
// 串行挂载场景:父级已保证在视口内,免 IntersectionObserver
if (immediate) {
const kick = () => el.classList.add('reveal--in')
if (typeof requestAnimationFrame === 'function') {
el.__revealRaf = requestAnimationFrame(() => {
el.__revealRaf = requestAnimationFrame(() => {
el.__revealRaf = 0
kick()
})
})
} else {
el.__revealTimer = setTimeout(kick, 16)
}
return
}
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
}
if (el.__revealRaf) {
cancelAnimationFrame(el.__revealRaf)
el.__revealRaf = 0
}
if (el.__revealTimer) {
clearTimeout(el.__revealTimer)
el.__revealTimer = 0
}
},
}
export default reveal