jlmakes / scrollreveal 是目前使用量最多的滚动揭示动画库,也是非常好用,只需要添加对应 className 即可。
但是在 react 中会有第一次加载闪烁的问题。
首先你要把需要动态揭示的 dom 隐藏起来,我这里假定所有需要滚动揭示的节点都附加上 j-scroll-reveal_
这个 class :
.j-scroll-reveal_ {
visibility: hidden;
}
之后写一个滚动揭示的 hooks :
import { useEffect, useRef } from 'react'
import ScrollReveal from 'scrollreveal'
const REVEAL_CLASS = 'j-scroll-reveal_'
export const useScrollReveal = () => {
// 把全局实例初始化起来
const ins = useRef(
ScrollReveal() as scrollReveal.ScrollRevealObject & {
destroy?: () => void
}
)
// 把隐藏恢复的锁
const isStyleAddedRef = useRef(false)
useEffect(() => {
const ref = ins.current
ref.reveal(`.${REVEAL_CLASS}`, {
// .... other options
interval: 150,
// 在开始揭示的钩子里把 dom 展示出来
beforeReveal: () => {
if (isStyleAddedRef.current) {
return
}
isStyleAddedRef.current = true
const style = document.createElement('style')
style.innerHTML = `.${REVEAL_CLASS} {visibility: visible;}`
document.getElementsByTagName('head')[0].appendChild(style)
},
})
return () => {
// https://scrollrevealjs.org/guide/whats-new.html
ref?.destroy?.()
}
}, [])
}
注意,现在 @types/scrollreveal
这个 type 库没有 destory
等最新的方法的 type,可以自己补一下。
核心思路是先通过全局样式隐藏掉,再开始揭示的时候展示出来,这样子就可以完美避免闪烁的问题。
有人会问使用 useLayoutEffect
在渲染前操作可不可以?当然不可以,滚动揭示是异步的,和 hooks 时机无关。
虽然这种 hack 方式能解决问题,但在大部分业务项目里,一般不会用到滚动揭示。
如果确实有这种需求,也可以考虑使用一些动画库来实现滚动渐入,这方面就比较广了,但需要考虑好时机,需不需要自己管理 IntersectionObserver
等。