uni-app 自帶原生導航欄,在pages.json裏配置。
原生導航的體驗更好,渲染新頁面時,原生導航欄的渲染無需等待新頁面dom加載,可以在新頁面進入動畫開始時就渲染。
原生導航還可以避免滾動條通頂,並方便的控制原生下拉刷新。
通過pages.json的配置,可以簡單的、跨端的、高性能的開發業務。
但原生導航欄的擴展能力有限的。尤其是微信下,沒有提供太多導航欄的配置。
在App下,pages.json裏每個頁面的app-plus下可以設置titleNView等更多參數,可以得到比微信小程序更豐富的擴展性。
另外,開發者也可以在必要時取消原生導航欄,使用view自行繪製導航欄。
原生導航欄的通用配置
原生導航欄的配置,均在pages.json裏,每個page下面的style配置中的navigationBar各個參數配置,即爲通用配置,小程序、app、h5均生效。參考https://uniapp.dcloud.io/collocation/pages?id=style
全局取消原生導航欄
在pages.json的globalStyle裏,有個navigationStyle設置,默認是default,即帶有原生導航欄。
也可以設置爲custom。
在設爲custom後,所有頁面都沒有原生導航。
但在微信小程序裏,右上角始終都有一個膠囊按鈕。
很多微信小遊戲界面上也沒原生導航欄,但有膠囊按鈕。
一般App裏不會使用這個參數配置。建議個別頁面單獨設置不使用原生導航,具體見下。
單獨去除原生導航欄
自微信客戶端 7.0.0 起、App端HBuilderX 2.0.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
App單獨去除原生導航欄
複製代碼{
"path": "pages/log/log",
"style": {
"navigationBarTitleText": "hello",
"app-plus": {
"titleNView": false
}
}
}
在App去除原生導航欄後,小程序端側仍保有原生導航欄。
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;
}
給原生導航欄添加自定義按鈕
注意:按鈕的點擊事件需要在頁面監聽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推薦使用字體圖標。
如果按鈕使用的漢字或英文較長,推薦把字體改小一點,或者調節按鈕寬度、padding等值。
配置button的背景顏色爲透明:background:'rgba(0,0,0,0)'
以上代碼在hello uni-app的模板-頂部導航標題欄中有示例。
原生導航欄自定義按鈕帶紅點和角標
複製代碼{
"path" : "nav-dot/nav-dot",
"style" : {
"navigationBarTitleText" : "導航欄帶紅點和角標",
"app-plus" : {
"titleNView" : {
"buttons" : [
{
"text" : "消息",
"fontSize" : "14",
"redDot" : true
},
{
"text" : "關注",
"fontSize" : "14",
"badgeText" : "12"
}
]
}
}
}
}
以上代碼在hello uni-app的模板-頂部導航標題欄中有示例。
原生導航欄自定義按鈕帶下拉選擇(城市選擇)
複製代碼{
"path" : "nav-city-dropdown/nav-city-dropdown",
"style" : {
"navigationBarTitleText" : "導航欄帶城市選擇",
"app-plus" : {
"titleNView" : {
"buttons" : [
{
"text" : "北京市",
"fontSize" : "14",
"select" : true,
"width" : "auto"
}
]
}
}
}
}
以上代碼在hello uni-app的模板-頂部導航標題欄中有示例。
導航欄上的原生搜索框
原生導航欄支持放置原生搜索框,可點擊直接彈出軟鍵盤,也可以點擊後跳轉到新頁面搜索。
因代碼較多,此處不列,請參考hello uni-app的模板-頂部導航標題欄示例。
如需動態修改searchInput,或者獲取searchInput的placehold,參考uni-app動態修改App端導航欄
配置原生導航欄的透明漸變
原生導航欄還支持透明漸變效果,頁面剛載入時沒有導航標題,頁面內容通頂到狀態欄裏,頁面向下滾動後標題欄漸變出現。
複製代碼{
"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)'
原生導航欄繪製圖片
通過在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的模板-頂部導航標題欄中有示例。
通過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
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"
}]
}
}
}
App側使用plus.nativeObj.view自定義原生導航欄
注意:從HBuilderX 1.9.10起提供了subnvue,比使用plus.nativeObj.view自定義原生導航欄更加方便。詳見上一節。
titleNView提供的配置,雖然比微信多不少,但有時仍然無法滿足某些場景的需求,比如在titleNView中畫一個選項卡。
此時有3種處理方式。1. 使用plus.nativeObj.view的api自定義titleNView。2. 頁面採用nvue,即weex方式製作。3. 取消原生導航,使用view自行繪製(見上)。
本節先說方式1. 使用plus.nativeObj.view
plus.nativeObj是5+引擎提供的輕量原生渲染引擎,其中plus.nativeObj.view一個自定義性很強的對象,以下簡稱nview。
規範文檔是:www.html5plus.org/doc/zh_cn/nativeobj.html#plus.nativeObj.View
nview是一個基於canvas理念的繪製引擎,在一塊畫布上自行繪製、覆蓋、擦除。
nview可以畫出任何界面、線條、矩形、文字、圖片、包括原生的input輸入框。
其實我們所看到的各種界面對象控件,在計算機底層都是繪圖引擎基於draw字、draw圖、draw線條來做的。
與weex相比,nview並不夠強,nview沒有dom概念,不支持內部滾動。
其實titleNView,包括原生tabbar、cover-view,他們的底層實現都是基於nview的。
獲取當前頁面的titleNView對象,參考http://ask.dcloud.net.cn/article/35036
同時上述參考文章中還有一個給titleNView的右上角畫一個小紅點的例子。
開發者製作的示例,如何給原生導航欄頂部畫一個原生input:http://ask.dcloud.net.cn/article/35201
取消原生導航欄後,使用前端標籤組件模擬繪製導航欄
不管是全局取消原生導航欄,還是在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>
Ps:若頁面不需要標題欄,只需一個狀態欄的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自定義組件模擬導航欄,會有很多性能體驗問題:
- 加載不如原生導航快
- 下拉刷新無法從自定義的導航欄組件下面下拉
- 必須取消頁面的bounce效果,否則滾動到頂時再拖屏幕,在iOS上發現title也被拖下來了。
- 滾動條會通頂
所以除非不得以,不要使用全局取消原生導航欄的做法。
如必須使用,注意如下幾點: - 涉及到導航欄高度的css儘量放置在App.vue裏面以提高渲染速度(css渲染順序:先渲染App.vue裏面的css,再渲染頁面css)
- 狀態欄顏色應設置默認顏色,若非必要,不建議修改其顏色
- 減少在組件中使用 :style="" 的使用以提高性能
- 下拉刷新使用circle方式,並設置offset,讓下拉刷新的圈從指定位置開始下拉,具體見pages.json配置文檔
有個高頻場景是App首頁的title自定義,如果實現的效果很個性化,那麼使用plus.nativeObj.view的方案會過於複雜,由於首頁並不存在新頁面進入立即渲染的壓力,所以App首頁如果要大幅定製,推薦使用前端view繪製,而不是使用plus.nativeObj.view。
如果把自定義導航封裝成組件,雖然多個頁面引入方便,但性能下降,因爲這種自定義組件的加載是晚於頁面基本元素的,會導致新頁面進入動畫時無法渲染title。
所以導航條這種要求在動畫期渲染的東西,儘量不要使用自定義組件方式。
在hello uni-app示例中有各種導航欄的源碼。
在擴展ui中有前端自定義導航欄。
在模板中有各種原生的導航欄。
大多數情況複製這些代碼就夠了。