✨ 第十三章:Framer Motion 微動畫實作與極致體驗
在先前的章節中,我們用 Tailwind CSS 實作了非常漂亮的玻璃擬態 (Glassmorphism) 打卡按鈕。如果你仔細看 Tailwind 的程式碼,你可能會看到類似 transition duration-300 hover:-translate-y-1 這樣的語法。
這能製造出一種「滑鼠移過去,按鈕微微浮起來」的簡單效果,這在傳統網頁中已經算及格了。
但是,當你的系統是建置在 React (Vite/Next.js) 上的,而且你的目標是讓這個「網頁」摸起來、用起來,完全就像是一個安裝在手機裡的「原生 App (Native App)」,那麼傳統的 CSS 漸變絕對無法滿足你。
這時候,你需要一套更強大、更符合現實世界物理定律的神級動畫庫:Framer Motion。
彈簧物理:為什麼有些 App 按起來特別爽?
什麼是「物理感知」的動畫? 想像一下在真實世界中,當你用力按下一顆實體的機械按鈕,它會被往下壓扁;當你的手放開時,裡面的彈簧會把按鈕彈回來,而且還會微微震動幾下。 這種具有「慣性」與「阻尼」的回饋感,會讓使用者的大腦產生一種「我真的有按到東西」的確定感。
利用 Framer Motion,我們不需要去寫複雜的數學公式,只需加上幾個屬性就能輕鬆做到這點。
首先,安裝 Framer Motion:
npm install framer-motion
接著,把原本的 <button> 換成 <motion.button>:
// 引入 Framer Motion 的 motion 元件
import { motion } from "framer-motion";
export default function PunchButton() {
return (
<motion.button
// 🖱️ 滑鼠懸浮時:微微放大到 1.05 倍 (呼吸感)
whileHover={{ scale: 1.05 }}
// 👆 點擊壓下時:縮小到 0.95 倍 (這就是實體按鍵感!)
whileTap={{ scale: 0.95 }}
// 設定動畫的物理屬性:使用彈簧 (spring),設定彈性係數
transition={{ type: "spring", stiffness: 400, damping: 17 }}
className="bg-gradient-to-r from-blue-500 to-indigo-600 text-white font-bold py-6 px-12 rounded-full shadow-lg shadow-blue-500/30"
>
<div className="text-3xl mb-1">👆</div>
<div className="text-xl tracking-widest">上班打卡</div>
</motion.button>
);
}
當你在手機上點擊這顆按鈕時,它那 Q 彈的回饋,絕對會讓挑剔的老闆愛不釋手!
🪄 Vibe Coding 實戰:讓 AI 幫你寫出炫砲出場動畫
除了按鈕的回饋感,現代化的 UI 設計也極度要求「出場動畫」。 當員工按下打卡成功後,與其讓成功提示框「硬生生地閃現」在畫面上,我們更希望它能像是一張卡片一樣,優雅地滑進來。
不要去死背這些參數,直接交給 AI!
🔥【Vibe Prompt 實戰咒語】
我正在使用 React 與 Framer Motion。當打卡成功時,我需要顯示一個打卡成功的提示卡片 (SuccessCard)。請幫我寫這個元件,需求如下:1. 使用 <motion.div> 來包裝整個卡片。2. initial (初始狀態):卡片在畫面下方 50px 的位置 (y: 50),且透明度為 0 (opacity: 0)。3. animate (動畫狀態):卡片移動到原本位置 (y: 0),透明度變成 1。4. exit (離場狀態,如果卡片被關閉):往下掉落並消失。5. transition (動畫過渡):使用 spring (彈簧) 效果,stiffness 設定為 300,damping 設定為 20 (讓它有一點Q彈感)。6. 內部 UI 請用 Tailwind 寫一個綠色風格、帶有打勾圖示的精美成功提示框。
AI 會產出這段讓畫面瞬間變高級的動畫卡片:
import { motion, AnimatePresence } from "framer-motion";
export default function SuccessCard({ isVisible }: { isVisible: boolean }) {
return (
// AnimatePresence 是用來讓元素「消失」時也能播動畫的神器
<AnimatePresence>
{isVisible && (
<motion.div
initial={{ y: 50, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
exit={{ y: 20, opacity: 0 }}
transition={{ type: "spring", stiffness: 300, damping: 20 }}
className="bg-green-50 border border-green-200 p-6 rounded-2xl shadow-lg flex items-center space-x-4 max-w-sm mx-auto"
>
<div className="bg-green-100 p-3 rounded-full">
<span className="text-2xl">✅</span>
</div>
<div>
<h3 className="font-bold text-green-800 text-lg">打卡成功!</h3>
<p className="text-green-600 text-sm">辛苦了,祝你有美好的一天。</p>
</div>
</motion.div>
)}
</AnimatePresence>
);
}
把這段程式碼放進去,當打卡 API 回傳成功後,這張充滿彈性的卡片就會從下方 Q 彈地跳出來。這種充滿「儀式感」的體驗,正是你說服客戶「為什麼這套系統值這個價錢」的最強武器。
🎉 line-punch-web 前端實戰大結業!
狂賀!到這裡為止,你已經完全掌握了開發一個「具備商業價值 LIFF 前端應用」的所有精華。 從 LIFF 的身份驗證機制、玻璃擬態 (Glassmorphism) 的美學設計、Zustand 的狀態管理,一直到 Framer Motion 極致流暢的物理微動畫。你現在已經可以做出一個讓客戶愛不釋手、比原生 App 還要順暢的手機版介面了!
但光有漂亮的外表是不夠的。打卡時間可以竄改嗎?如果員工在自家床上打卡怎麼辦? 在未來的進階課程中,我們還會探討如何利用經緯度 (Geolocation) 以及 Wi-Fi 限制,寫出無懈可擊的防作弊打卡邏輯!
喝口水,準備好迎接最後的 CrewAI 智能體挑戰吧!