Open2

Next.js怠惰な実装まとめ

masa5714masa5714

だるいものを簡単に実装する方法があればここに書いていきます。

masa5714masa5714

スクロール位置がある要素を超えたら、画面外から要素を出現させる

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; 的な要件で実現したい場合

https://zenn.dev/masa5714/scraps/39a9123ac53c7f

違いはoffsetを設定するだけ!