こういうのを作ってみました😀
demo
How to
ステップバイステップで、このUI の実装方法を紹介していきます!
今回このUI を実装は Framer Motion, Next.js, Tailwind CSS を使いました。
アニメ部分のキーであるFramer Motion は、ポピュラーで高度なアニメーションを簡単に実装できるライブラリです。
クリックで拡大・移動させる
Framer Motion のいいところは、はじまりと最後だけ定義してもちゃんと動くところです。
👇を見てみてください、これだけで拡大・移動させることができます。
import { useState } from 'react'
import { motion } from 'framer-motion'
export default function SampleCard() {
const [isSelected, setIsSelected] = useState(false)
return (
<>
<motion.li
layoutId="card"
className="text-blue-600 font-bold w-72 p-7 rounded-md bg-blue-400 list-none mx-auto"
onClick={() => setIsSelected(true)}
>
<motion.h1>Hello</motion.h1>
</motion.li>
{isSelected && (
<motion.div
layoutId="card"
className="text-green-600 font-bold w-8/12 h-96 p-7 rounded-md bg-green-400 mx-auto"
>
<motion.button className="text-white" onClick={() => setIsSelected(false)}>
close
</motion.button>
<motion.h1>Hello from Big</motion.h1>
</motion.div>
)}
</>
)
}
ドラッグを認識させる
ドラッグを認識させるのも簡単です。motion タグに、drag 属性とonDrag 属性を設定するだけで認識できます。
<motion.div
layoutId="card"
className="text-green-600 font-bold w-8/12 h-96 p-7 rounded-md bg-green-400 mx-auto"
drag="x"
onDrag={() => {
console.log("Dragged !")
}}
>
ドラッグでイベントを発生させる
ドラッグイベントを更新して、座標に応じてイベントを発生させます。
<motion.div
layoutId="card"
className="text-green-600 font-bold w-8/12 h-96 p-7 rounded-md bg-green-400 mx-auto"
drag="x"
onDrag={(e, {offset}) => {
// 初期座標からx軸で100px 以上移動したら
if (offset.x > 100) {
console.log("Wow !")
}
}}
>
スワイプで切り替わるようにする
あとは、イベントで切り替わるようにハンドルしたら完了です!
AnimatePresence タグでアンマウントされたときまで、自動でアニメーションを適用できます。
import { useState } from 'react'
import { motion } from 'framer-motion'
import { AnimatePresence } from 'framer-motion'
export default function SampleCard() {
const items = [{ id: "left" }, { id: "right" }]
const [selected, setSelected] = useState("")
return (
<>
<ul className = "flex mx-auto gap-5">
{items.map(item => (
<motion.li
key={item.id}
layoutId={item.id}
className="text-blue-600 font-bold w-72 p-7 rounded-md bg-blue-400 list-none"
onClick={() => setSelected(item.id)}
>
<motion.h1>Hello</motion.h1>
</motion.li>
))}
</ul>
{selected !== "" && (
<AnimatePresence>
<div className = "h-screen w-screen z-20 flex justify-center items-center">
<motion.div
key={selected}
layoutId={selected}
className="text-green-600 font-bold absolute w-8/12 h-96 p-7 rounded-md bg-green-400"
drag="x"
onDrag={(e, {offset}) => {
console.log("Dragged !")
// 初期座標からx軸で100px 以上移動したら
if (offset.x > 100) {
setSelected("right")
} else if (offset.x < -100) {
setSelected("left")
}
}}
>
<motion.button className="text-white" onClick={() => setSelected("")}>
close
</motion.button>
<motion.h1>Hello from {selected}</motion.h1>
</motion.div>
</div>
</AnimatePresence>
)}
</>
)
}
おわりに
いかがだったでしょうか?
Framer Motion を使う際に参考にしていただければ幸いです!
このQiita の記事は、BitStar のアドイベントカレンダーのとして掲載しました。
ぜひ、他の記事も見ていただければ嬉しいです!
BitStar では、React, Rails を使ってサービスを開発中です🧑💻
ご興味がある方は以下からご確認ください!