在移動端頁面中,由於屏幕空間有限,導航條扮演著非常重要的角色,提供了快速導航到不同頁面或功能的方式。用戶也通常會在導航條中尋找他們感興趣的內容,因此導航條的曝光率較高。在這樣的背景下,提供一個動態靈活的導航條,為產品賦能,變得尤其重要。 ...
背景
在移動端頁面中,由於屏幕空間有限,導航條扮演著非常重要的角色,提供了快速導航到不同頁面或功能的方式。用戶也通常會在導航條中尋找他們感興趣的內容,因此導航條的曝光率較高。在這樣的背景下,提供一個動態靈活的導航條,為產品賦能,變得尤其重要。
使用原生導航欄現狀
拿iOS原生導航條為例,導航條作為頁面進出棧的根視圖連接器,以及生命周期的管理器。尤其是在作為webView Controller的父容器的時候,面對webview中h5頁面靈活的的路由屬性,以及一些難料的異常情況,原生很難也不便於頻繁操作根試圖容器,因此也產生了一些性能差、體驗差、開發成本高、測試場景難覆蓋等問題。安卓也有類似情況。
1、性能問題
•ssr
預渲染時,無法對原生導航條進行預載入。對於百億,便宜包郵等使用ssr預渲染的頻道,因為原生導航欄無法進行預載入,導致上屏較慢等問題。
2、開發/測試成本高
•原生導航條生命周期耦合。原生導航條作為webviewController的根容器,一旦操作時機不當,很可能影響到線上頁面,而且最大的問題在於這種場景測試很難覆蓋。比如:window.href.url
使用這種方式更新當前頁面時,由於不同頻道操作同一根導航條,會引發不可預知的問題;
•場景有限。站外場景無法使用原生導航條,一些業務方往往需要單獨處理站內外,造成開發資源浪費。
3、體驗差
•webview初始化時會預置一個預設的導航條,然後根據前端配置,再去設置導航條的不同樣式,無法避免的存在一個過渡期,體驗較差。
•window.location.reload()
刷新當前頁面的時候,即便是在js中隱藏了導航條,webview
為了相容一個線上問題,執行reload時此時會先展示原生導航條,直到執行了js的隱藏邏輯,才會被隱藏,體驗較差。
4、難擴展造成營銷資源浪費
•無法擴展交互動效。得益於移動端頁面中,導航條得天獨厚的位置,產品往往希望有更生動的交互性,來提高曝光、粘性、活動觸達率等。比如導航欄上掛載搜索框、以及吸頂、延伸動畫、沉浸式、炫酷的營銷icon等等。遺憾的是原生系統導航條不能全部支持,其實無論從視圖層級上來說,還是從導航條職責上來說,apple
並不希望過多操作導航欄上的元素。也就造成了高曝光位置的資源浪費。
5、依賴性強
•因為要依賴原生JS橋,就一定會存在版本限制問題。造成需求迭代慢,甚至隨著時間的推移,版本卡口原因無跡可尋,代碼調整戰戰兢兢,版本審核慢、周期長等問題。
解決方案
基於原生導航條現狀,百億補貼頻道沉澱出了通用H5導航條組件@pango/navigation-bar
,具有以下優勢:
1、性能好
•支持ssr預渲染,上屏較快。
2、開發/測試成本低
•人力節省百分之90%以上,以plus 95折為例,對接只需0.5/人日。
•無場景限制。可用於站內外,ssr以及csr場景,無需站內外多次開發。
•可配置。 @pango/navigation-bar
使用config的形式配置item,這麼做的好處是一旦業務需求改動,只需調整配置,無需調整組件邏輯,極大降低開發和測試成本。另外如果你使用主站的webview並且配置了config,那麼只需要簡單的改動config,代碼遷移成本低。
•導航條在頻道內和其他普通樓層無異,生命周期隔離清晰,不會影響別的頁面,測試成本低。
•單向數據流設計,外部數據變化,組件UI及時響應,不存在原生的操作視窗問題,開發體驗佳;
3、用戶體驗好
•生命周期和其他樓層保持同步,規避了原生容器和H5頁面天然的生命周期無法同步的問題,也就不存在兩者之間的過渡問題,體驗佳。
4、靈活定製
•採用左、中、右、狀態欄、導航欄分層設計的模式,支持傳入React.ReactElement,比原生定製性更強,可靈活定製目前站內絕大部分導航條樣式以及交互動畫,合理高效利用導航條資源;
5、機型、系統相容性好
•參考原生導航欄異形屏適配方案,參考原生絕對佈局思路,完美適配摺疊屏、異形屏。
•iOS9 - 最新 、Android5 - 最新均相容性良好,未發現線上相容異常。
6、不對外依賴
純手工打造,未使用第三方庫,不會對宿主造成依賴衝突,隨時改動隨時發佈不存在版本控制,最大程度的降低和隔斷對原生容器的版本依賴。
異常處理
原生導航條作為根試圖容器,容器內子視圖異常不會影響根試圖的展示,所以不用特殊處理html下載失敗,js執行異常,服務掛掉等異常情況。但是H5導航條遇到這些異常情況,也要保證用戶可以點擊返回按鈕返回上一頁。
百補方案
目前方案已和通天塔以及hybrid團隊打通,方案如下:
異常場景1:業務js執行異常。
• @pango/navigation-bar組件使用a標簽渲染返回按鈕,保證js執行異常時依然展示返回按鈕,並且能正常響應返回事件。
•業務展示兜底錯誤頁時,會使用導航條兜底數據渲染導航條確保可返回上一級。
異常場景2:webview載入html失敗。
為了消除上面提到的過渡問題,業務鏈接中新增了qurey
參數hideNavi=1
,原生webview會通過該欄位在webview出現之前隱藏導航條。但是因此也引發了一個風險:html載入失敗時,會造成無頭的問題。因此需要webview配合改造,一旦監測到html載入失敗,原生webview要展示原生導航條。
異常場景3:通天塔服務異常。
同樣是場景2中的問題,需要通天塔配合改造通天塔服務異常的場景:依據鏈接中hideNavi
欄位添加返回按鈕或者通知webview展示預設導航條。
競品和兄弟頻道對比
觀察多個競品以及兄弟頻道,發現在上述的異常場景2、3下,均未做特別處理,展示無頭錯誤頁。如果此時原生禁用了右滑返回手勢,頁面將無法返回上一級,這無異是一個非常嚴重的缺陷(事實上有些競品頁面以及我們某些頻道確實無法返回上一級)。
線上項目
目前使用該組件的項目:百億補貼、月黑風高、PLUS95折。
線上成果展示
設計思路
參考原生navigationBar
的設計思路,把整個導航欄分為左、右、中
三個區域,左、右區域根據內容自適應寬度,剩餘空間為中間區域。左右區域接受items數組,可根據item介面協議設置左右的items,協議可自定義圖片、尺寸、事件、間距、下拉菜單、是否動畫響應等,已預設包含了關註、返回、更多、頻道logo等常用元素,當然如有需要也可以自定義一個React.ReactElement
。中間區域只接受React.ReactElement
,你可以自由定製元素,傳入navigation-bar
即可,一張圖片一段文字,或者是一個搜索框……不管是伸縮或者是上滑吸頂,都可自定義。
@pango/navigation-bar
該組件使用react + ts開發,大小隻有4.1K。
文件結構:
使用方式
安裝
npm i @pango/navigation-bar --registry=http://registry.m.jd.com
配置
你可以自由配置items除了"follow", "more","back","logo"
,這些已知的元素外還可以設置type:"common",
是一個通用類型的item;
scrollCallBack
會回調上滑比例,可根據該比例做交互動畫;
import {
BACK_ICON,
FEEDBACK_ICON,
FEEDBACK_URL,
INavigationParams,
MORE_ICON,
RULE_ICON,
SHARE_ICON,
} from "@pango/navigation-bar";
setH5NavigationButton = (headerData) => {
const extend = headerData?.navigationBar?.extend;
const followInfo = headerData?.navigationBar?.followInfo;
const follow = {
type: "follow",
collectionId: String(followInfo?.themeId),
gapWidth: 12,
width: 55,
height: 22,
};
const moreItem = {
type: "more",
menuBackgroundColor: "white",
img: MORE_ICON,
title: "更多",
menuList: [],
};
moreItem.menuList.push({
icon: RULE_ICON,
title: "規則頁",
menuEventData: extend?.guideUrl,
});
moreItem.menuList.push({
icon: SHARE_ICON,
title: "分享",
type: "share",
menuEventData: extend?.share,
});
const backItem = {
type: "back",
img: BACK_ICON,
canClick: !margicWindow,
title: "返回",
};
const backLogo = {
type: "logo",
img: DEFAULT_LOGO,
isAnimation: true,
gapWidth: 5,
width: 176,
height: 34
};
const navBarParams: INavigationParams = {
leftItems: [],
rightItems: [],
backgroundColor: "#FD4D00",
navHeight: this.status.navHeight,
};
navBarParams.leftItems.push(backItem, backLogo);
navBarParams.rightItems.push(moreItem, follow);
navBarParams.titleImgItem = TitleSearch({});
navBarParams.scrollCallBack = (scale) => {
this.setStatus({
navigationBarParams: Object.assign(this.status.navigationBarParams, {
titleImgItem: TitleSearch({ isCollapse: scale === 1 })
})
});
}
return navBarParams;
};
titleImgItem
特別註意titleImgItem,這個屬性是導航條中間區域的展示內容,TitleSearch
是百億補貼的搜索框,你可以參考該元素自定義中間區域。
掛載
import { INavigationParams, NavigationBar } from "@pango/navigation-bar";
import "@pango/navigation-bar/lib/navigation-bar.scss";
css
.nav-bar {
width: 750px;
z-index: 1;
top: 0px;
}
<NavigationBar
className="nav-bar"
params={data.navParams}
barHeight={200} //自定義導航欄高度
event={do somethings}
/>
遇到了哪些問題
Q:若原生導航條隱藏,此時異常怎麼辦?
異常分為以下3類:
異常場景1:業務js執行異常。
• @pango/navigation-bar組件使用a標簽渲染返回按鈕,保證js執行異常時依然展示該標簽,並且能正常相應出棧事件。
•業務展示兜底錯誤頁時,會使用導航條兜底數據渲染導航條。
異常場景2:webview載入html失敗。
為了消除上面提到的過渡問題,業務鏈接中新增了qurey
參數hideNavi=1
,原生webview會通過該欄位在webview出現之前隱藏導航條。但是因此也引發了一個風險:html載入失敗時,會造成無頭的問題。因此需要webview配合改造,一旦監測到html載入失敗,原生webview要展示原生導航條。
異常場景3:通天塔服務異常。
同樣是場景2中的問題,需要通天塔配合改造通天塔服務異常的場景:依據鏈接中hideNavi
欄位添加返回按鈕或者通知webview展示預設導航條。
若發現其他異常,麻煩提醒我。
Q:摺疊屏怎麼適配?
摺疊屏適配一直是前端適配的噩夢,噩夢的根本原因在於:寬度於高度的比例非常值,前端佈局是往往會把px轉換成vw,因此造成了異形屏適配難的問題。
•參考原生系統導航欄的絕對佈局方案:@pango/navigation-bar
把導航條拆分為狀態欄和導航欄上下兩部分, 導航條寬度屏幕自適應,導航條高度跟隨設備變化,並採用大寫的PX
單位來固定元素尺寸。根據協議item寬高、間距仍可自定義,但是大寫的PX
保證了item不會隨著屏幕寬度而異常變化。
navigation-bar {
width: 750px; // 會轉換成vw
height: 44PX; // 不會轉換成vw
display: flex;
position: absolute;
.left-items-bg {
margin-left: 16PX; // 不會轉換成vw
height: 22PX;
margin-top: 11PX;
width: fit-content;
display: flex;
align-items: center;
justify-content: center;
}
}
Q:原生導航條優化?
現狀中的幾個異常場景,仍需要webview配合一起整改,所以目前整改方案為:
業務鏈接中新增qurey
參數hideNavi=1
,此時 webview通過該欄位在webview 出現之前隱藏導航條。由webview負責整改,跟版12.1.4。
開源計劃
經安全部門審核之後,會向外開源。
迭代計劃
•導航條在移動端頁面中的重要性無需多言,我們最終的目的是面向全集團,和通天塔以及hybrid團隊,一起打造一根規範通用的H5導航欄,如果你在使用過程中發現一些我們沒有考慮到的異常場景或者設計規範,請與我聯繫,我們共同完善。
•目前該組件下拉刷新還是要依賴原生的下拉刷新事件,後期會定製H5自己的下拉刷新。
•一個規範的UI組件應該是一個有嚴格UI設計規範的,比如間距,字體大小、圖片規範等。但是一期的設計中我們為了靈活,通過協議把UI把控留給了用戶,也希望後面的迭代開發中融入更多規範的設計語言。
作者:京東零售 張松超
來源:京東雲開發者社區 轉載請註明來源