爲了提升業務人員操作管理後臺的體驗,花了點時間進行響應式的改造,緊急情況時,掏出手機就能工作。
利用CSS3的媒體查詢,就能根據不同屏幕的尺寸採用不同的樣式來渲染,目前使用的移動端屏幕閾值爲750px。
爲了便於管理,基於Less的語法,聲明瞭一個常量,專門記錄屏幕尺寸。
@mobile-screen: ~"(max-width:750px)";
我們當前使用的管理後臺基於UmiJS3.X和Ant Design 3.X。
一、結構改造
首先是管理後臺整體結構的改造,包括左邊的菜單欄,右邊的快捷按鈕,登錄信息等。
1)菜單欄
左邊的菜單在手機界面還是蠻佔地方的,默認情況下需要將其隱藏,還有那張Logo圖,也需要隱藏,最大限度的將區域留給菜單。
在下面的代碼中,當URL的路徑發生變化時,判斷屏幕尺寸,如果當前是顯示狀態,那麼就更新成隱藏狀態。
// 響應式處理 const mobileHandle = () => { // 屏幕尺寸小於750的就認爲是移動設備的屏幕 if (window.screen.width <= 750 && !siderFold) { dispatch({ type: "app/switchSider" }); } }; // 當路徑變化時,隱藏菜單欄 useEffect(() => { mobileHandle(); }, [location.pathname]);
在Chrome的控制檯,切換成手機屏幕時,右半部分會出現擠壓的問題。
可以將右半部分設置爲絕對定位,脫離正常流,再向左偏移菜單欄的寬度就能避免內容被擠壓。
.main { width: 100%; position: absolute; left: 250px; }
2)快捷按鈕
快捷按鈕有3個,PC界面這塊的高度是固定的,並且是橫向佈局。移動端的屏幕比較窄,更適合縱向佈局。
並且爲了節約空間,登錄後的暱稱,也隱藏了,免得破壞佈局。
3)全局樣式
這些按鈕默認是沒有上下間距的,需要手動添加,例如修改Ant Design 的下拉框、搜索框、日期選擇框的下邊距,存儲在 global.css 文件中。
.ant-select, .ant-input-search, .ant-calendar-picker { margin-bottom: 5px; }
有一點需要注意,不能將上述這些樣式寫在 less 文件內,因爲在JavaScript文件中引用(CSS in JS)時,默認會帶各種隨機後綴。
@media @mobile-screen { .ant-select, .ant-input-search { margin-bottom: 5px; } } /* 編譯結果 */ @media (max-width: 750px) { .ant-select___1JpXW, .ant-input-search___WeNgK { margin-bottom: 5px; } }
全局聲明需要權衡,當涉及的頁面很多時,也許某條樣式會破壞某處的結構。
二、頁面改造
在頁面中使用了大量的組件,包括自定義和第三方的,默認情況下,都不支持響應式,需要進行手動改造。
1)表格
管理後臺包含很多表格,這些表格都會包含很多列,直接平鋪會將頁面撐開,出現左右滾動條。
在觀察Ant Design表格滾動的源碼後,發現了一個 max-content 關鍵字,表示寬度就是內容的長度。
.ant-table-body, /* 表格 */ .ant-tabs-tabpane { /* 標籤欄切換內容 */ overflow-x: scroll; width: 100%; -webkit-overflow-scrolling: touch; } .ant-table-body table, .ant-tabs-tabpane table { width: max-content; }
在表格的父級元素中聲明橫向滾動,就能避免佈局被破壞了。
2)內聯樣式
在之前的頁面開發中,很多組件的寬度都是以內聯的方式聲明的。當時的確很方便,但是現在改造給我製造了障礙。
如果直接在CSS文件中聲明,那麼特殊性不會比內聯的高,也就不會生效,所以得用另一種方式。
後面就想用腳本來做樣式的更新,腳本比較好寫。但是需要考慮一種情況。
那就是頁面初始化時不存在的DOM元素,需要點擊或其他交互後才能被添加進來。
需要監聽DOM的變化,自然就想到了MutationObserver,在下面的代碼中會監聽 body 元素的直系後代的DOM變化。
useEffect(() => { const isMobile = window.screen.width <= 750; // 選擇器,數字框,文本框,卡片 const selector = ".ant-input-number[style],.ant-input[style],.ant-calendar-picker[style],.ant-card[style],.ant-input[style]"; if (!isMobile) return; const callback = function (mutationsList, observer) { // 爲了響應式,將style中的寬度修改成 100% const nodes = document.querySelectorAll(selector); [...nodes].forEach((item) => { if (item.style.width && item.style.width != "100%") { item.style.width = "100%"; } }); }; // 觀察器的配置,直接子節點的更改 const config = { childList: true }; const observer = new MutationObserver(callback); // 觀察目標節點 observer.observe(document.body, config); }, []);
3)彈框
在PC界面中,彈框中的內容會比較多,高度也會被撐開。
當在移動端顯示時,會超過屏幕的底部,無法看到彈框中的內容。
可以手動的聲明彈框的高度,利用calc()函數,以及vh單位,100vh就是視口高度的100%。
height: calc(100vh - 100px)