在開發導航欄之前,建議把官方的這篇導航欄示例看完,基本大部分功能都能滿足,有代碼及示例圖,很好的案例:導航欄示例應用。
uni-app 自帶原生導航欄,在pages.json里配置。原生導航的體驗更好,渲染新頁面時,原生導航欄的渲染無需等待新頁面dom加載,可以在新頁面進入動畫開始時就渲染。原生導航還可以避免滾動條通頂,並方便的控制原生下拉刷新。通過pages.json的配置,可以簡單的、跨端的、高性能的開發業務。
但原生導航欄的擴展能力有限的。尤其是微信下,沒有提供太多導航欄的配置。在App下,pages.json里每個頁面的app-plus下可以設置titleNView等更多參數,可以得到比微信小程序更豐富的擴展性。
另外,開發者也可以在必要時取消原生導航欄,使用view自行繪制導航欄。
一、原生導航欄
1、原生導航欄的通用配置
原生導航欄的配置,均在pages.json里,每個page下面的style配置中的navigationBar各個參數配置,即為通用配置,小程序、app、h5均生效。參考https://uniapp.dcloud.io/collocation/pages?id=style
2、全局取消原生導航欄
在pages.json的globalStyle里,有個navigationStyle設置,默認是default,即帶有原生導航欄。
也可以設置為custom,在設為custom后,所有頁面都沒有原生導航。
但在微信小程序里,右上角始終都有一個膠囊按鈕,很多微信小游戲界面上也沒原生導航欄,但有膠囊按鈕。
一般App里不會使用這個參數配置。建議個別頁面單獨設置不使用原生導航,具體見下。
3、單獨去除原生導航欄
支持通過如下方法取消單獨一個頁面的原生導航欄。但小程序右上角膠囊按鈕仍然去不掉。頁面配置 navigationStyle 為 custom:
{ "path" : "pages/log/log", "style" : { "navigationStyle":"custom" } }
二、原生導航欄在App側的擴展
微信小程序的設計里,沒有給原生導航提供太多自定義能力,在開發App時是不夠用的。pages.json里,每個page下面的style下面還有一個子擴展節點:app-plus。
這個節點定義了在5+App環境下,也即iOS、Android環境下,增強的配置。其中有一個子節點titleNView,這個是5+規范里webview頁面的原生導航窗體規范。
參考https://uniapp.dcloud.io/collocation/pages?id=app-plus
1、App去除導航欄后改變狀態欄樣式
App因為默認為沉浸式,去除導航欄后,頁面頂部會直通到狀態欄的區域,可能出現如下需求:
- 改變狀態欄文字顏色:設置該頁面的 navigationBarTextStyle 屬性,可取值為 black/white。如果想單獨設置顏色,App端可使用plus.navigator.setStatusBarStyle設置。部分低端Android手機(4.4)自身不支持設置狀態欄前景色。
- 改變狀態欄背景顏色:通過繪制一個占位的view固定放在狀態欄位置,設置此view的背景顏色,即可達到想要的效果,uni-app提供了一個狀態欄高度的css變量,具體參考:http://uniapp.dcloud.io/frame?id=css%E5%8F%98%E9%87%8F
以下為示例:
<!-- #ifdef APP-PLUS -->
<view class="status_bar">
<view class="top_view"></view>
</view>
<!-- #endif --> .status_bar { height: var(--status-bar-height); width: 100%; background-color: #F8F8F8; } .top_view { height: var(--status-bar-height); width: 100%; position: fixed; background-color: #F8F8F8; top: 0; z-index: 999; }
2、給原生導航欄添加自定義按鈕
注意:按鈕的點擊事件需要在頁面監聽onNavigationBarButtonTap事件。頁面監聽代碼如下:
// 頁面監聽代碼如下:
export default { data() { return {} }, onNavigationBarButtonTap() { console.log("點擊了自定義按鈕"); } } // pages.json配置如下:
{ "path": "pages/log/log", "style": { "navigationBarTitleText": "hello", "app-plus": { "titleNView": { "buttons": [{ "text": "\ue534", "fontSrc": "/static/uni.ttf", "fontSize": "22px" }] } } } }
buttons的text推薦使用字體圖標。如果按鈕使用的漢字或英文較長,推薦把字體改小一點,或者調節按鈕寬度等值。配置button的背景顏色為透明:background:'rgba(0,0,0,0)'。
3、原生導航欄自定義按鈕帶紅點和角標
{ "path" : "nav-dot/nav-dot", "style" : { "navigationBarTitleText" : "導航欄帶紅點和角標", "app-plus" : { "titleNView" : { "buttons" : [ { "text" : "消息", "fontSize" : "14", "redDot" : true }, { "text" : "關注", "fontSize" : "14", "badgeText" : "12" } ] } } } }
4、原生導航欄自定義按鈕帶下拉選擇(城市選擇)
{ "path" : "nav-city-dropdown/nav-city-dropdown", "style" : { "navigationBarTitleText" : "導航欄帶城市選擇", "app-plus" : { "titleNView" : { "buttons" : [ { "text" : "北京市", "fontSize" : "14", "select" : true, "width" : "auto" } ] } } } }
5、導航欄上的原生搜索框
原生導航欄支持放置原生搜索框,可點擊直接彈出軟鍵盤,也可以點擊后跳轉到新頁面搜索。因代碼較多,此處不列,請參考hello uni-app的模板-頂部導航標題欄示例。如需動態修改searchInput,或者獲取searchInput的placehold,參考uni-app動態修改App端導航欄
6、配置原生導航欄的透明漸變
原生導航欄還支持透明漸變效果,頁面剛載入時沒有導航標題,頁面內容通頂到狀態欄里,頁面向下滾動后標題欄漸變出現。
{ "path": "pages/log/log", "style": { "navigationBarTitleText": "hello", "app-plus": { "titleNView": { "type": "transparent" } } } }
實際上可用的titleNView設置還有很多,詳細的api見http://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewTitleNViewStyles
透明漸變的導航欄的button圖標有一個默認的灰色背景圈,防止背景圖和按鈕前景顏色相同導致按鈕無法看清。如果要去掉這個灰色背景圖,可以配置button的背景顏色為透明:background:'rgba(0,0,0,0)'
7、原生導航欄繪制圖片
titleNView新版配置可以直接配圖片,還支持Gif圖。但這里提供一個黑科技寫法,通過在titleNView里配置tags,可以實現導航欄繪制圖片的效果:
{ "path" : "nav-image/nav-image", "style" : { "app-plus" : { "titleNView" : { "titleText" : "", "tags" : [ { "tag" : "img", "src" : "/static/nav.png", "position" : { "left" : "auto", "top" : "auto", "width" : "110px", "height" : "26px" } } ] } } } }
通過配置 tags 除了可以繪制圖片,還可以繪制更多豐富的內容,如:richtext(富文本)、font(文本)、input(輸入框)、rect(矩形區域)。詳情參考:titleNView、tags。以上代碼在hello uni-app的模板-頂部導航標題欄中有示例。
8、通過setStyle方式動態修改原生導航欄樣式
如果需要js動態修改導航欄,uni有跨端的api可修改標題、背景色、前景色。這部分是app、小程序、h5都支持的,參考https://uniapp.dcloud.io/api/ui/navigationbar。
對於app側擴展的設置,比如自己添加的buttons,則需使用plus的js api來動態設置。在App端可以通過得到webview對象,通過setStyle方法重新設置,包括修改webview對象的titleNview屬性,以達到修改標題欄按鈕文字及樣式的功能。具體參考:https://ask.dcloud.net.cn/article/35374
9、App側使用subnvue自行繪制原生導航
nvue其實是weex上補充了uni的api。uni-app支持使用nvue頁面,也就是weex原生引擎,繪制頂部的原生導航欄。
在hello uni-app的API-界面示例中,有subnvue示例,里面頂部導航欄是漸變色的,這就是subnvue的原生導航欄。在pages.json的配置如下:
{ "path": "subnvue/subnvue", "style": { "app-plus": { "titleNView": false, "subNVues": [{ "id": "nav", "path": "subnvue/subnvue/nav", "type": "navigationBar" }] } } }
從HBuilderX2.6.3起,titleNView直接支持了背景圖、漸變色,不再需要通過subnvue的方式了。而且性能比subnvue更好。
10、取消原生導航欄后,使用前端標簽組件模擬繪制導航欄
不管是全局取消原生導航欄,還是在App下某個頁面取消原生導航,如果還想自己繪制一些個性化的title,往往會使用view組件。尤其是App的首頁,頂部經常有各種特殊設置,此時需要自己使用前端技術來繪制導航。
導航欄應該是由狀態欄和標題欄構成,狀態欄的高度為 var(--status-bar-height) 此變量為uni-app框架提供僅在在css生效,標題欄的高度設為88px,整個狀態欄的高度應為: calc(var(--status-bar-height) + 88px)(upx主要針對寬度,高度無所謂還可以使用px)
.title-contents{ height: calc(var(--status-bar-height) + 88px); } .status{ height: var(--status-bar-height); } .titles{ height: 88px; }
狀態欄和標題欄都應固定在頁面頂部,需設置 position:fixed,標題欄的top應為狀態欄的高度
.top-view{ width: 100%; position: fixed; top: 0; } .titles{ top: var(--status-bar-height); }
繪制的返回箭頭需要綁定點擊事件,返回上一個頁面
<view class="titleLeftButton" @click="backButton"></view> methods:{ backButton(){ uni.navigateBack() } }
以下為導航欄組件的部分代碼
<template>
<view class="title-contents">
<view class="top-view status" :style="{background:statusColor}"></view>
<view class="_top titles" :style="{background:statusColor}">
<view class="titleLeftButton" @click="backButton" v-if="showLeftButton"></view>
<view class="titleText" :class="titleClass">{{titleText}}</view>
<view class="titleRightButton" @click="rightButton" v-if="showRightButton"></view>
</view>
</view>
</template>
<script> export default { props:{ titleText:{ type:String, default:"" }, statusColor:{ type:String, default:"#8F8F94" }, showLeftButton:{ type:Boolean, default:true }, showRightButton:{ type:Boolean, default:false } }, methods:{ backButton(){ uni.navigateBack() }, ... } } </script>
<style> ... .top-view{ width: 100%; position: fixed; top: 0; } </style>
若頁面不需要標題欄,只需一個狀態欄的view占位,那么只需在頁面添加一個view即可不需要引入外部組件以免影響性能。
<view class="status-contents">
<view class="status top-view"></view>
</view>
//css
.status-contents{ height: var(--status-bar-height); } .top-view{ width: 100%; position: fixed; top: 0; } .status{ height:var(--status-bar-height); }
uni ui里有前端實現的自定義導航欄組件,推薦不要自己寫,直接用寫好的組件,https://ext.dcloud.net.cn/plugin?id=52,hello uni-app的uni ui中也有示例。
三、注意事項
取消原生導航欄后,自己使用HTML自定義組件模擬導航欄,會有很多性能體驗問題:
1、加載不如原生導航快
2、下拉刷新無法從自定義的導航欄組件下面下拉。除非使用前端做下拉刷新,但性能不如自帶的原生下拉刷新。
3、必須取消頁面的bounce效果,否則滾動到頂時再拖屏幕,在iOS上發現title也被拖下來了。
4、滾動條會通頂。所以除非不得以,不要取消原生導航欄。
如必須使用,注意如下幾點:
(1)涉及到導航欄高度的css盡量放置在App.vue里面以提高渲染速度(css渲染順序:先渲染App.vue里面的css,再渲染頁面css)
(2)如果是深色造成閃屏,需要在pages.json的titleNView下配置webview的背景色
(3)狀態欄顏色應設置默認顏色,若非必要,不建議修改其顏色
(4)減少在組件中使用 :style="" 的使用以提高性能
(5)下拉刷新使用circle方式,並設置offset,讓下拉刷新的圈從指定位置開始下拉,具體見pages.json配置文檔
有個高頻場景是App“首頁”的title自定義,如果實現的效果很個性化,那么使用plus.nativeObj.view的方案會過於復雜,由於首頁並不存在新頁面進入立即渲染的壓力,所以App首頁如果要大幅定制,推薦使用前端view繪制,而不是使用plus.nativeObj.view。
如果把自定義導航封裝成組件,雖然多個頁面引入方便,但性能下降,因為這種自定義組件的加載是晚於頁面基本元素的,會導致新頁面進入動畫時無法渲染title。
所以導航條這種要求在動畫期渲染的東西,盡量不要使用自定義組件方式。
在hello uni-app示例中有各種導航欄的源碼:在擴展ui中有前端自定義導航欄,在模板中有各種原生的導航欄,大多數情況復制這些代碼就夠了。