✨ 第十三章: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 智能體挑戰吧!

解鎖完整教學內容

本章為付費內容。加入專案即可解鎖超過 5000 字的深度解析,包含 10 個以上神級 Prompt 與真實 Source Code 範例!