前言
在公司的 Angular project 使用 onResize()
監聽 screen viewport changed 時,發生了一些預期外的問題
經過了一個禮拜的搗鼓,以及 Sr. engineer 的指導,發現可以使用這個 ResizeObserver API,雖然專案最後沒有採用,我們用了另一個算是微繞路的方法,不算是 Work around,可也不太能百分百說是正解,欲知詳情如何就請看下去吧 👀
問題
Web APP 在手機上轉動方向後,透過 onResize()
window event 的 call back 來做後續的動作時,沒有抓到元素變動後的正確位置
原因是 onResize()
event 是針對 window viewport 發生變動,就會被 fired,並不是針對元素有變動才 fired,所以有機率會發生想要計算的目標元素還沒更新完畢時就收到 call back,這時候抓到的值可能會是還沒改變時的樣子
相關討論可以到永遠的好朋友 StackOverflow 上看
- https://stackoverflow.com/questions/44484547/screen-width-screen-height-not-updating-after-screen-rotation
- https://stackoverflow.com/questions/1649086/detect-rotation-of-android-phone-in-the-browser-with-javascript/6603537#6603537
用 onOrientationChange()
window event 也是一樣的,它也是針對 window viewport 的改變,只是多了判斷角度,無法讓我們接收 DOM 真的改變後的 call back
Whenever the viewport is drawn at a different angle compared to the device’s natural orientation (refer to this spec)
這個問題發生的機會在小專案可能不高,因為從 window 一變動到 DOM updated 的時差應該是非常短的,我們後來認為應該跟目前的專案太肥了導致在 rotating 的 perf 很差有關
解法
使用 JS 剛推出不久的 API - ResizeObserver 直接監聽 DOM 變動,就能完美解決這個問題😇
目前幾乎所有瀏覽器都支援了 (ResizeObserver 背後其實就是基於 RxJS 的 Observable 概念)
使用它除了能解決我上述提到的問題,還能夠改進不必要的 call back check 次數
在大部分的使用情境,我們用 window event 去監聽大小變動都是想要 update layout (如果有需要),但有時候元素大小沒有被變動因為視窗變動了,window resize event 還是會被 fired
延伸閱讀
library
剩下的小問題就是在 Angular 10 + Typescript 中並沒有找到 ResizeObserver type,Compiler 會報錯 (不過是可以使用的)
大部分推薦的是引入這個已經存在一陣子的 resize-observer-polyfill open source
TS code snippet
如果不想引入 3rd party library,在 Angular + ts code 內要使用 any
type 宣告,並且在 initiate 的地方的前一行用 // @ts-ignore
去避免 compiler error
1 | private resizeObserver: any; |
Trick
senior 同事提供的另外一個方法是加 setTimeout()
,但不要加任何秒數 (通常不建議去設置任何秒數去預期某些行為會在這個秒數內結束),只需等這個 tick 結束,看看能不能抓到目標元素正確的位置
1 | 'window:orientationchange') ( |
會稱作 Trick 的原因是可能不是萬用解,我試過放在 onResize()
內,還是沒有辦法抓到正確的數值,後來發現加在 onOrientationChange()
內有辦法得到正確的值
正好我們要解的 issue 只有 在 orientation change 後才需要✌️✌️✌️
如果加入 ResizeObserver,需要考慮 backward compatibility,萬一這個瀏覽器版本不支援的話,要有對應的 fall back action,後來就決定比起加入 ResizeObserver,使用這個方法才最適合我們目前的需求
後記
這次經驗又讓我學到新東西,對於前端開發還不能說是特別熟稔,目前接觸了一年多下來發現真的要很認真與時俱進,既有的基礎核心都還沒補完,就要更新知識,在不同語言間跳轉的話我又容易忘記前端用過的東西,然後瀏覽器種類、版本、裝置又這麼多組合要考慮= =…以後誰在跟我說前端很簡單的都給我滾