refer :
https://github.com/angular/angular/issues/10929
https://stackoverflow.com/questions/41280471/how-to-implement-routereusestrategy-shoulddetach-for-specific-routes-in-angular
一切從這個開始.
剛開始接觸 SPA 的朋友們可能會很不習慣 scroll position 在游覽器后退的時候並不會智能的滾動回之前頁面的位置.
這時就會出現上面這張圖片的需求了.
我個人認為, 做 SPA 交互設計就不要走回跳轉頁面的老套路線. 應該尋求創新而不是模擬從前的功能.
不過現實就是, 創新不出來..只能走老路...哈哈
下面來聊聊模擬的技術.
我們知道 SPA 是通過 history.push 來替換游覽器地址的,然后通過路由器匹配出組件, 在渲染和替換頁面.
即使是游覽器后退也是通過監聽 onpopstate, 然后匹配路由, 渲染組件...
所以整個過程都被 javascript l攔截處理了,游覽器基本上什么也干不了. (從前游覽器會在 url 替換時 scroll to top, 在后退時 scroll to 之前的位置)
那么我們就得替代游覽器工作了.
首先建一個全局的滾動條.
在前進時要 scroll to top, 我們可以攔截 router change 事件,然后 scrollTop = 0
在后退時, 我們要恢復位置就必須做記入.
那么我們在 router change 時, 把當前的 scrollTop 記入起來.
這樣就行了.
呃... 哪有這么容易...
游覽器后退的時候, 其實是使用之前的緩存資料的, 所以你會感覺它渲染很快馬上就回滾到位了.
但 SPA 每一次都會從新渲染頁面, 組件初始化-> ajax -> 渲染 -> 這時候你才可以滾動到之前的位置..
來, 介紹 angular 的 RouteReuseStrategy !
這個東西可以讓組件所有 state 和渲染好的 html 被存起來. 然后快速的調出來用.
no more 組件初始化-> ajax -> 渲染.
export declare abstract class RouteReuseStrategy { abstract shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean; abstract shouldAttach(route: ActivatedRouteSnapshot): boolean; abstract retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null; abstract shouldDetach(route: ActivatedRouteSnapshot): boolean; abstract store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle | null): void; }
這個是它的類,我們繼承然后替換掉 provider 就可以被 angular 調用了.
angular 會在每一次 router change 的時候調用它.
angular 路由就是棵樹, 當 url 從 a/b/c/d 切換到 a/e/f/g 時.
shouldReuseRoute 會被觸發. angular 會讓你去對比看是否要 reuse
a vs a
b vs e
c vs f
d vs g
一般情況下 a vs a 自然時 reuse
b vs e 就替換, 而一旦 parent 被替換, 那么所有 child 自然也是被替換的
替換一旦發生, 就會有某些組件要被丟棄 destroy, 這時 shouldDetech, store 就會被調用, 用於緩存這些已經渲染完成即將被丟棄的組件.
有組件被丟棄自然有組件需要進來替補, 而這時 shouldAttach,retrieve 就會被調用, 用來調出緩存的組件.
所以流程是這樣 :
1. 是否替換 ?
2. 替換發生, 有組件離去, 有組件加入
3. 離去的組件, 我們可以緩存
4. 加入的組件, 我們可以使用緩存好的組件.
替換->緩存->重用 就是整體的核心了.