taos
Version:
TAOS - Tailwind CSS Animation on Scroll Library
92 lines (80 loc) • 2.5 kB
JavaScript
(function() {
const debounce = (fn, delay) => {
let timeoutId = null
return () => {
clearTimeout(timeoutId)
timeoutId = setTimeout(fn, delay)
}
}
const throttle = (fn, delay) => {
let waiting = false
return () => {
if (!waiting) {
fn()
waiting = true
setTimeout(() => waiting = false, delay)
}
}
}
const reset = element => {
if (element.className !== element.dataset.taosClass) {
element.className = element.dataset.taosClass
}
}
const before = element => element.className = element.className.replaceAll('taos:', '')
const initElement = element => {
if (!element.className.includes('taos-init')) {
element.dataset.taosClass = element.className + ' taos-init'
reset(element)
}
element.className += ' !duration-[0ms] !delay-[0ms]'
before(element)
return {
element,
once: getComputedStyle(element)['animation-iteration-count'] === '1',
offset: parseInt(element.dataset.taosOffset || 0)
}
}
let elements = []
let innerWidth = window.innerWidth
let scrollY = window.scrollY
const refreshTriggers = throttle(() => {
elements.forEach(el => el.trigger = el.element.getBoundingClientRect().top - window.innerHeight + el.offset + scrollY)
}, 250)
const refresh = () => {
elements = []
document.querySelectorAll('[class*="taos"]').forEach(el => elements.push(initElement(el)))
refreshTriggers()
requestAnimationFrame(handleScroll)
}
const handleScroll = () => {
scrollY = window.scrollY
elements.forEach(({element, trigger, once}) => {
if (trigger < scrollY) {
reset(element)
}
else if (!once && element.className.includes('taos:')) {
before(element)
}
})
refreshTriggers()
}
const handleResize = () => {
if (innerWidth !== window.innerWidth) {
innerWidth = window.innerWidth
refresh()
}
}
refresh()
addEventListener('scroll', throttle(handleScroll, 32))
addEventListener('orientationchange', refresh)
addEventListener('resize', debounce(handleResize, 250))
const observer = new MutationObserver(mutations => {
mutations.forEach(({target}) => {
if (target.className && !target.className.includes('taos-init') && target.className.includes('taos:')) {
elements.push(initElement(target))
}
})
})
observer.observe(document, {attributes: true, childList: true, subtree: true})
})()