在檔案 projects\storefrontlib\layout\config\default-layout.config.ts 裡,定義了各個螢幕尺寸所對應的 breakpoint:
export const defaultLayoutConfig: LayoutConfig = {
breakpoints: {
xs: 576,
sm: 768,
md: 992,
lg: 1200,
xl: {
min: 1200,
},
},
};
注意這個 breakpoint 和程式語言裡的斷點沒有關係。
breakpoint.service.ts 的 getBreakpoint 方法,提供了根據當前螢幕寬度返回最合適的 breakpoint:
以這個 id 為 trigger 的按鈕為例,它是完全 css 驅動的:
這個按鈕的 css:
btn btn-action btn-block dialog-trigger
該按鈕在 lg 這個 breakpoint 情況下,會被設定為 display:none:
而 Spartacus 應用程式碼怎麼知道當前的螢幕尺寸對應的 break point 呢?
答案是我們自己實現的 breakpoint.service.ts.
首先定義列舉型別 BREAKPOINT:
export enum BREAKPOINT {
xs = 'xs',
sm = 'sm',
md = 'md',
lg = 'lg',
xl = 'xl',
}
然後根據當前程式碼的執行環境進行計算:
breakpoint$: Observable<BREAKPOINT> = isPlatformBrowser(this.platform)
? this.winRef.resize$.pipe(
map((event) => this.getBreakpoint((<Window>event.target).innerWidth)),
distinctUntilChanged()
)
: of(this.fallbackBreakpoint);
constructor(
protected winRef: WindowRef,
protected layoutConfig: LayoutConfig,
@Inject(PLATFORM_ID) protected platform: any
) {}
如果當前執行在瀏覽器環境下,isPlatformBrowser(this.platform) 返回 true,那麼進入三元表示式前面的分支,呼叫 this.getBreakpoint 根據當前螢幕的 innerWidth,獲取對應的 breakpoint.
同時,一旦有 resize 事件發生,會自動重新計算新的 breakpoint. 每次 resize 事件發生時,產生的 event 物件 event.target 指向 Window 物件,該物件的 innerWidth 即是新的螢幕寬度。
如何捕捉螢幕的 resize 事件?
get resize$(): Observable<any> {
if (!this.nativeWindow) {
return of(null);
} else {
return fromEvent(this.nativeWindow, 'resize').pipe(
debounceTime(300),
startWith({ target: this.nativeWindow }),
distinctUntilChanged()
);
}
}
這裡我們使用了 rxJs 的 fromEvent 和 debounce, 將 window 物件產生的 resize 事件,做了一個 300 毫秒的限流,意思是當 resize 事件觸發後,如果300毫秒之內並沒有新的 resize 事件發生時,再把這個 resize 事件,交給 Observable 執行鏈的下游處理,即重新獲取 breakpoint.
如果當前程式碼在伺服器端 Node.js 環境中執行,進入三元表示式問號後面的分支:of(this.fallbackBreakpoint);
返回最小螢幕尺寸對應的 breakpoint,這也體現了 mobile first 的設計思路。
更多Jerry的原創文章,盡在:"汪子熙":