iT邦幫忙

2026 iThome 鐵人賽

DAY 26
0
Build on Google AI

《30天打造喵語日誌:Gemini API × Vibe Coding 實戰》系列 第 26

Day 26:【使用者體驗】載入狀態與 Skeleton 骨架屏美化

  • 分享至 

  • xImage
  •  

在大型語言模型(LLM)的應用場景中,從使用者按下送出到模型完成多模態推論與結構化回傳,通常存在約 2~3 秒的運算延遲。如果這段期間介面毫無反饋,或者只有一顆生硬旋轉的 Spinner,使用者很容易產生「系統是不是卡死、當機了?」的焦慮感。

今天我們將專注於 使用者體驗(UX)的細節打磨,為《喵語日誌》打造專屬的貓咪微光骨架屏(Skeleton UI),搭配動態輪播文案與全域防重複提交機制,把原本枯燥的等待轉化為有溫度的陪伴互動!

為什麼 AI 應用的 Loading 體驗至關重要?

在打造 AI 驅動的產品時,載入體驗的好壞直接影響使用者的留存意願:

  • 消除操作不確定感: 透過預先佔位的骨架氣泡,明確告訴使用者「系統已確實收到訊息,貓咪正在組織語言」。

  • 維持介面結構穩定: Skeleton 預先模擬了真實對話氣泡的高度與結構,避免資料回傳瞬間產生突兀的版面跳動(Layout Shift)。

  • 增加趣味微互動: 在等待期間輪播隨機的貓咪碎碎念,提升產品的情緒價值與品牌陪伴感。

核心實作重點與程式碼

1. 微光掃過(Shimmer)與交錯跳動動畫

在全域樣式檔 src/index.css 中定義線性漸層掃過動畫與三點交錯縮放的 Keyframes:

@import "tailwindcss";

/* 🎯 Day 26: 貓咪骨架屏微光 (Shimmer) 與跳動動畫 */
@keyframes shimmer {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

.animate-shimmer {
  background: linear-gradient(
    90deg,
    rgba(255, 228, 230, 0.4) 0%,
    rgba(255, 255, 255, 0.8) 50%,
    rgba(255, 228, 230, 0.4) 100%
  );
  background-size: 200% 100%;
  animation: shimmer 1.6s infinite linear;
}

@keyframes bounce-delay {
  0%, 80%, 100% { transform: scale(0.6); opacity: 0.35; }
  40% { transform: scale(1); opacity: 1; }
}

.animate-dot-1 { animation: bounce-delay 1.4s infinite ease-in-out 0s; }
.animate-dot-2 { animation: bounce-delay 1.4s infinite ease-in-out 0.2s; }
.animate-dot-3 { animation: bounce-delay 1.4s infinite ease-in-out 0.4s; }

2. 封裝動態輪播的骨架屏元件

ChatContainer.tsx 中封裝 CatSkeletonLoader。我們設定 setInterval 每 1.8 秒自動輪換等待文案,並呈現帶有 Shimmer 效果的粉嫩佔位長條:

const WAITING_TEXTS = [
  "貓咪正在認真思考中...🐾",
  "正在聞這段日記的味道...🐟",
  "喵喵正在組織可愛的語言...✨",
  "貓咪搖了搖尾巴,馬上就好囉...🌿",
]

function CatSkeletonLoader() {
  const [textIndex, setTextIndex] = useState(0)

  useEffect(() => {
    const timer = setInterval(() => {
      setTextIndex((prev) => (prev + 1) % WAITING_TEXTS.length)
    }, 1800)
    return () => clearInterval(timer)
  }, [])

  return (
    <div className="flex items-start gap-2.5 transition-all duration-300 ease-out animate-in fade-in slide-in-from-bottom-2">
      <CatAvatar size="sm" />
      <div className="max-w-[85%] sm:max-w-[75%] rounded-2xl rounded-tl-sm bg-rose-50/90 border border-rose-200/70 p-3.5 shadow-sm space-y-2.5">
        <div className="flex items-center gap-2 text-xs text-rose-500 font-medium">
          <span>{WAITING_TEXTS[textIndex]}</span>
          <div className="flex gap-1 items-center">
            <span className="h-1.5 w-1.5 rounded-full bg-rose-400 animate-dot-1 inline-block" />
            <span className="h-1.5 w-1.5 rounded-full bg-rose-400 animate-dot-2 inline-block" />
            <span className="h-1.5 w-1.5 rounded-full bg-rose-400 animate-dot-3 inline-block" />
          </div>
        </div>

        <div className="h-3 w-44 sm:w-56 rounded-md animate-shimmer" />
        <div className="h-3 w-28 sm:w-36 rounded-md animate-shimmer" />
      </div>
    </div>
  )
}

3. 防重複提交(Double-Submit Prevention)

發送請求後,將輸入框、圖片選擇鈕、心情選擇器及送出按鈕統一加上 disabled={isLoading} 屬性,避免使用者因為連點造成多次請求、額外消耗 API 配額或導致狀態錯亂:

<input
  type="text"
  value={input}
  disabled={isLoading}
  onChange={(e) => setInput(e.target.value)}
  onKeyDown={handleKeyDown}
  placeholder={isLoading ? "貓咪正在回覆中,請稍候..." : "跟喵喵說點什麼吧…"}
  className="... disabled:bg-stone-100 disabled:text-stone-400 disabled:cursor-not-allowed"
/>

<button
  type="button"
  onClick={handleSend}
  disabled={(!input.trim() && !selectedImage) || isLoading}
  className="... disabled:opacity-40 disabled:cursor-not-allowed"
>
  <Send className="h-4 w-4" />
</button>

成果驗收

完成更新並推送至 GitHub 後,Vercel 觸發自動建置完成:

等待狀態:按下送出瞬間,輸入框立即鎖定並切換 Placeholder 提示「貓咪正在回覆中...」,對話列表下方流暢滑入帶有動態文案與 Shimmer 微光的粉紅貓咪氣泡。

回覆呈現:API 資料回傳後,骨架屏無縫切換為正式的貓咪管家卡片,所有輸入控制器同步恢復為可操作狀態。

https://ithelp.ithome.com.tw/upload/images/20260827/20178708dasSuY2BQC.png
📷 送出訊息後,畫面上出現帶有微光掃過效果的貓咪骨架屏與輪播文案。

實作心得

在功能開發初期,我們通常最在意的是「API 能不能通」與「資料能不能存」;但真正決定一款產品成熟度的,往往是這些看似微小卻極其關鍵的 UX 細節。

透過 Skeleton UI 與微互動動畫,不僅有效緩解了 LLM 推論延遲帶來的空白卡頓感,更強化了《喵語日誌》本身的療癒陪伴感。好的載入狀態設計不是單純掩飾延遲,而是把等待轉化為品牌個性的一部分!

結語

今天我們成功補齊了 AI 應用的載入體驗,使整體的互動手感更加流暢完整。

進入鐵人賽的最後倒數!明天我們將把部署好的網址交給真實使用者試玩,並根據第一手的操作反饋,針對行動端響應式排版(RWD)、手機鍵盤適配與互動細節進行敏捷調優,敬請期待!

明天見,喵~ 🐾


上一篇
Day 25:雲端實戰!Vercel 自動化部署與生產環境 Gemini API 除錯紀實
系列文
《30天打造喵語日誌:Gemini API × Vibe Coding 實戰》26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言