![]()
Frandy 今天花了大半天,盯著一個動畫時間錯位的 bug。光帶劃過時間軸,本該精準擊中每個節點閃爍,實際卻像醉漢走路——偏左、偏右、時早時晚,完全沒規律。
他重寫了四遍邏輯。四次。
問題不在代碼寫得蠢,在于他一直在用兩套互不相干的坐標系做同一道題。
兩套坐標系,各說各話
Frandy 的時間軸組件有三層:橫向卡片軌道、可拖拽折疊的卡片、以及三條脊柱軌道上跑的霓虹光帶。光帶移動用 viewport 空間計算——從可視區域左邊緣開始的像素距離。節點位置卻用 card 空間——從整個軌道最左端累加所有卡片寬度,包括已經被滾出屏幕的那些。
只有當滾動位置為 0 且所有卡片完全展開時,這兩個數字才碰巧相等。
用戶稍微滾動一下,或者折疊一張卡片,光帶和節點的"同一位置"就變成了兩個完全不同的坐標。Frandy 的前三次重寫都在優化計算精度,試圖用更復雜的數學讓兩套坐標系對齊。第四次他放棄了,直接讓瀏覽器告訴他答案。
第四次重寫:停止計算,開始測量
核心改動只有一行:用 getBoundingClientRect() 取代手動累加寬度。這個方法返回元素相對于視口的實際渲染位置,和光帶使用的坐標系天然一致。
代碼變成這樣:每次滾動、卡片寬度變化、篩選條件切換或窗口縮放時,標記一個臟標志(dirty flag),確保每幀動畫最多測量一次。光帶的位置和節點的位置現在從同一個源頭讀取——瀏覽器已經算好的真實像素位置。
Frandy 在博客里說,「光帶現在每次都精準擊中節點。因為它讀的是現實。」
這個修復的諷刺之處在于:他花了四小時試圖用數學打敗瀏覽器,最后發現瀏覽器早就給出了正確答案。
時間軸的其余細節
這個組件的交互密度不低。桌面端支持橡皮筋拖拽,帶彈簧物理效果;第一張卡片 sticky 固定;雙擊打開詳情面板;卡片角標顯示當前索引;折疊狀態下有個"呼吸"效果的窺視圓點提示可展開。
三條脊柱軌道上的光帶也有講究:彗星拖尾、速度變化、護送偏移、節點閃爍時帶旋轉和漣漪效果。未來卡片用顏色回退,動畫能干凈重啟。
主題系統做了完整的明暗模式,四種強調色可選。localStorage 記住用戶選擇,覆蓋管理后臺的默認設置。桌面端用下拉菜單,移動端是下滑面板,滾動時和返回頂部按鈕互斥顯示。
UI 層面還修了芯片/標簽欄邊框、重新對齊返回頂部按鈕、增加區塊間距和導航高度、優化文字透明度。
項目狀態與下一步
Frandy 的站點尚未上線。時間軸桌面版已完成,接下來是純設計迭代——給每個區塊做移動端布局,然后是管理后臺。不添加新功能,先把現有的一切打磨到位。
他給自己定了條規矩:上線前必須讓所有部分"看起來對"。
這個坐標空間 bug 的教訓,某種程度上也適用于產品決策。當你發現自己的推導和用戶的實際體驗持續偏離,問題可能不在執行層,而在你預設的框架本身。Frandy 選擇相信瀏覽器的渲染結果,而非自己維護的抽象計算——這種"向現實妥協"的思維方式,大概是前端工程師和產品經理的共通語言。
Frandy 的博客底部有個功能:模板快捷回復,用來快速回答常見問題或存儲可復用片段。他還沒寫這個功能的使用文檔——你覺得一個花了四小時才想起 getBoundingClientRect() 的開發者,會先寫文檔還是先寫代碼?
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.