iT邦幫忙

2026 iThome 鐵人賽

DAY 24
0
Modern Web

Vue 前端工程師視角看 Flutter Web系列 第 24

Day 24|案例研究:three.js 捲動式登陸頁轉 Flutter Web 觀察

  • 分享至 

  • xImage
  •  

模組五|建置與部署(Day 20–24)

模組五收尾,來做一個注定失敗的實驗。我手上另一個專案(claude-mobile,不在本系列 repo 裡)做過一個 three.js r128 的捲動式登陸頁:使用者往下捲,3D 場景的相機跟著推軌,文案一段段浮出——典型的 scroll-driven narrative。這種頁面是前端炫技首選,也是檢驗 Flutter Web 邊界的好題目:它整頁都是 canvas 繪製,理論上該是 Flutter 的主場,對吧?

Vue 怎麼做

那個 landing page 的骨架很標準:three.js 管 WebGL 場景,捲動進度當作動畫時間軸,DOM 文案層用 CSS 疊在 canvas 上面。核心迴圈十行講完:

// three.js r128 時代的寫法(claude-mobile 專案,此處以敘述重現)
const scrollProgress = () =>
  window.scrollY / (document.body.scrollHeight - window.innerHeight);

function animate() {
  const t = scrollProgress();           // 0 → 1
  camera.position.z = lerp(12, 4, t);   // 相機推軌
  camera.position.y = lerp(0, 2.5, easeOut(t));
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}
animate();

但生態才是這套玩法的真正主角:three.js 十幾年累積的範例庫、GLTF 載入器、shader 素材,加上 DOM 文案層天生可選取、可被爬蟲讀(登陸頁通常需要 SEO)。Vue 在這裡只是殼,重活是 three.js 和瀏覽器合力扛的。

Flutter Web 怎麼做

搬到 Flutter Web,選項盤點如下,每一條我都讓 agent 探過路:

**路線一:找 three.js 的 Dart 等價物。**社群有 three_dart、flutter_gl 這類移植,但版本落後 three.js 主線一大截、維護時斷時續。agent 很快撞牆:它可以流暢地翻譯相機推軌的數學,但套件缺件時,強型別編譯器只會誠實地告訴你「這個 API 不存在」。Day 1 獨家論點的反面在這裡現形——agent 翻得動 code,翻不動生態

**路線二:HtmlElementView 開洞,把 three.js 原封不動嵌回來。**技術上可行,但想清楚這是什麼:在 Flutter 的 canvas 裡挖一個洞、塞回一個 DOM 元素,裡面再跑一個 WebGL canvas,兩套渲染各畫各的,捲動事件還要跨界同步。為了用 Flutter 而把頁面主體交還給 JS——那當初為什麼要離開 Vue?

**路線三:放棄 3D,用 Flutter 自己的管線重做捲動敘事。**這條反而有驚喜。捲動驅動動畫在 Flutter 是 first-class 公民:

// ScrollController 驅動動畫進度,體感比監聽 window.scrollY 乾淨
class _LandingState extends State<Landing> {
  final _scroll = ScrollController();

  double get progress => _scroll.hasClients
      ? (_scroll.offset / _scroll.position.maxScrollExtent).clamp(0.0, 1.0)
      : 0.0;

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _scroll,
      builder: (_, __) => CustomPaint(
        painter: HeroPainter(progress), // 2D 場景照 progress 重繪
        child: buildCopyLayer(progress), // 文案層跟著同一個進度走
      ),
    );
  }
}

ScrollController、Transform、CustomPaint 這套組合拳,打 2D 視差、漸變、路徑動畫都很順——但就是沒有 3D 場景圖。WebGL 等級的內容,Flutter Web 目前沒有可靠的原生答案。

差異與坑

  1. 最諷刺的觀察:Flutter Web 整個 app 就是一張 canvas,理論上是 canvas 密集型 UI 的主場(Day 1 論點二),但「canvas 密集」的王者級場景——WebGL 3D——它反而接不住,因為十幾年的生態紅利全堆在 JS 那一側。
  2. **捲動物理是模擬的。**Flutter 的捲動是自己算的 physics,不是瀏覽器原生捲動。手感可以調得很像,但觸控板慣性、無障礙捲動、瀏覽器的 scroll anchoring 都要重新驗證——登陸頁這種「捲動即體驗」的頁面對此最敏感。
  3. **文案層的老問題回來了。**登陸頁要 SEO、要文字可選取,這兩件事 Day 1 就標記過是 Flutter Web 的硬傷,在這個案例裡直接命中要害。
  4. 結論不含糊:**這類頁面留在 Vue + three.js。**Flutter Web 適合的捲動敘事,是登入牆後、2D 為主、不需 SEO 的產品導覽——條件全部收斂回 Day 1 那棵決策樹。

小結與下一篇

一句話:Flutter Web 搬不動 three.js 的生態,這個實驗的價值不在成品,在於把「canvas 主場」論點的邊界實際量了出來。模組五到此收工,Day 25 進入最兇的戰場:SEO/SSR——先回顧 Nuxt 的 SSR/SSG 原理,再看 Flutter Web 拿什麼接招。

參考資料


上一篇
Day 23|部署踩坑:靜態託管、路由 rewrite、快取設定
下一篇
Day 25|Nuxt SSR/SSG 原理回顧
系列文
Vue 前端工程師視角看 Flutter Web26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言