Open2
Next.js怠惰な実装まとめ
だるいものを簡単に実装する方法があればここに書いていきます。
スクロール位置がある要素を超えたら、画面外から要素を出現させる
framer-motionの公式ドキュメントには意外とこれ載ってなかったので。
こういう感じのやつを下記の要件で作ります。
- リサイズ処理を勝手にやってくれる
- 3分で実装できる
必要なパッケージ
npm install framer-motion
実装例
FloatingPreview.tsx
"use client";
import { useRef, useState } from "react";
import { AnimatePresence, useMotionValueEvent, useScroll, motion } from "framer-motion";
export const FloatingPreview = () => {
// 表示状態を管理
const [isVisible, setIsVisible] = useState(false);
// どの要素を超えたら実行したいか
const triggerRef = useRef(null);
// 対象の要素までの距離を測る
const { scrollYProgress } = useScroll({
target: triggerRef
});
// スクロールイベント的なやつ
useMotionValueEvent(scrollYProgress, "change", (e) => {
// eの中にはtriggerRefまでの距離が格納されている。
// eが0になると表示条件を満たしたとみなす
// ちなみにeが0のときはこのイベントは自動的に止まってくれるすごいやつ!(リサイズ処理も勝手にやってくれる)
if (e === 0) {
setIsVisible(true); // 表示状態する
} else if (isVisible && e !== 0) {
setIsVisible(false); // 非表示状態にする
}
});
return (
<>
<div ref={triggerRef}></div>
<FloatingPreview isVisible={isVisible} />
</>
);
}
// にょきっと表示させたい要素を作る
const FloatingPreviewElement = ({isVisible = false}) => {
// AnimatePresence はDOMから要素が完全に消えるときもアニメーションを動かせるようにしてくれる。
// initialは初期値
// animateは表示の際に使われるアニメーション
// exitは非表示になる際に使われるアニメーション
// transitionはイージング(無くても動く。 https://easings.net/ などを参考にすると良い )
return (
<AnimatePresence>
{isVisible && (
<motion.div
initial={{
transform: "translateY(-100%)",
}}
animate={{
transform: "translateY(0)",
}}
exit={{
transform: "translateY(-100%)",
opacity: 0,
}}
transition={{ ease: [0.16, 1, 0.3, 1] }}
className="fixed top-0 w-full h-10 z-10 bg-white">
<p>はろー!</p>
</motion.div>
)}
</AnimatePresence>
);
}
実装のポイント
scrollYProgress
: これによって発火までの距離を監視でき、距離が無くなったら状態を変化させれば良いだけ。
useMotionValueEvent
: eが0になるとイベントが勝手に止まってくれるのありがたすぎる。リサイズも勝手にやってくれてマジで神。
<motion.div>
: この要素は motion.
の後は普通のHTMLタグだと思えばOK。h1やpにしたいなら、 <motion.h1>
とか <motion.p>
になる。HTMLタグに motion.
つけるだけでアニメーションが自由にできるようになっちゃう魔法だと思っておこう。
position:sticky; 的な要件で実現したい場合
違いはoffsetを設定するだけ!