Neil_HL
Neil_HL
  • 发布:2018-08-16 15:06
  • 更新:2019-06-12 13:34
  • 阅读:64415

uni-app导航栏开发指南

分类:uni-app

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里不会使用这个参数配置。
在App里,可以个别页面单独设置不使用原生导航,具体见下。

微信小程序单独去除原生导航栏

自微信客户端 7.0.0 起,微信小程序支持取消单独一个页面的原生导航栏,只保留右上角胶囊按钮,页面配置 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。
  • 改变状态栏背景颜色:通过绘制一个占位的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)'

自定义按钮带红点和角标

{  
    "path" : "nav-dot/nav-dot",  
    "style" : {  
        "navigationBarTitleText" : "导航栏带红点和角标",  
        "app-plus" : {  
            "titleNView" : {  
                "buttons" : [  
                    {  
                        "text" : "消息",  
                        "fontSize" : "14",  
                        "redDot" : true  
                    },  
                    {  
                        "text" : "关注",  
                        "fontSize" : "14",  
                        "badgeText" : "12"  
                    }  
                ]  
            }  
        }  
    }  
}  

自定义按钮带下拉选择(城市选择)

{  
    "path" : "nav-city-dropdown/nav-city-dropdown",  
    "style" : {  
        "navigationBarTitleText" : "导航栏带城市选择",  
        "app-plus" : {  
            "titleNView" : {  
                "buttons" : [  
                    {  
                        "text" : "北京市",  
                        "fontSize" : "14",  
                        "select" : true,  
                        "width" : "auto"  
                    }  
                ]  
            }  
        }  
    }  
}  

导航栏上的原生搜索框

原生导航栏支持放置原生搜索框,可点击直接弹出软键盘,也可以点击后跳转到新页面搜索。
因代码较多,此处不列,请参考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(矩形区域)。详情参考:titleNViewtags

通过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侧使用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侧使用nvue自行绘制导航

nvue其实是weex上补充了uni的api。
如果pages.json里配置了nvue页面的原生导航栏,则titleNView也是生效的。
如果去掉了titleNView,则自己绘制导航。
nvue没有性能问题,这位开发者分享了一篇文章:如何制作渐变颜色的导航栏http://ask.dcloud.net.cn/article/35111

取消原生导航栏后,如何自己使用标签组件将导航栏绘制出来

不管是全局取消原生导航栏,还是在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);  
}  

注意事项

取消原生导航栏后,自己使用HTML自定义组件模拟导航栏,会有很多性能体验问题:

  1. 加载不如原生导航快
  2. 下拉刷新无法从自定义的导航栏组件下面下拉
  3. 必须取消页面的bounce效果,否则滚动到顶时再拖屏幕,在iOS上发现title也被拖下来了。
  4. 滚动条会通顶
    所以除非不得以,不要使用全局取消原生导航栏的做法。
    如必须使用,注意如下几点:
  5. 涉及到导航栏高度的css尽量放置在App.vue里面以提高渲染速度(css渲染顺序:先渲染App.vue里面的css,再渲染页面css)
  6. 状态栏颜色应设置默认颜色,若非必要,不建议修改其颜色
  7. 减少在组件中使用 :style="" 的使用以提高性能
  8. 下拉刷新使用circle方式,并设置offset,让下拉刷新的圈从指定位置开始下拉,具体见pages.json配置文档

有个高频场景是App首页的title自定义,如果实现的效果很个性化,那么使用plus.nativeObj.view的方案会过于复杂,由于首页并不存在新页面进入立即渲染的压力,所以App首页如果要大幅定制,推荐使用前端view绘制,而不是使用plus.nativeObj.view。

如果把自定义导航封装成组件,虽然多个页面引入方便,但性能下降,因为这种自定义组件的加载是晚于页面基本元素的,会导致新页面进入动画时无法渲染title。
所以导航条这种要求在动画期渲染的东西,尽量不要使用自定义组件方式。

在hello uni-app示例中有各种导航栏的源码。
在扩展ui中有前端自定义导航栏。
在模板中有各种原生的导航栏。
大多数情况复制这些代码就够了。

28 关注 分享
823182755@qq.com 1486899711@qq.com 诗小柒 wzl16 三千烦恼丝瓜 Neil_HL Trust 442774948@qq.com i@jankerli.com 14536438@qq.com 18664698@qq.com 小明子 sonicsunsky@qq.com ccjuice 1249485588@qq.com shanjixiaboss@163.com hyd1272895358@163.com 1069668081@qq.com emeerwang@163.com dargon_wisdom@163.com 大灰灰 2274688674@qq.com gongkaixiong@qq.com 1501789852@qq.com 小张没有名字 逐鹿实验室 小黄鸭 skysowe

要回复文章请先登录注册

970109789@qq.com

970109789@qq.com

导航栏上加input 和 城市按钮, 如何让城市按钮处于左侧,input处于右侧
2019-06-12 13:34
uniapp棒棒的

uniapp棒棒的

回复 uniapp棒棒的:
看错了....,评论不能删除吗?
2019-06-05 16:40
uniapp棒棒的

uniapp棒棒的

"整个状态栏的高度应为: calc(var(--status-bar-height) + 88px)",这句话怎么理解啊,为什么是它们两个相加?
2019-06-05 16:27
15093568689@163.com

15093568689@163.com

回复 15093568689@163.com:
已解决
2019-06-01 15:45
15093568689@163.com

15093568689@163.com

如何修改顶部导航条的右侧按钮、图标或者搜索导航的左右边距?
2019-06-01 14:38
1046865524@qq.com

1046865524@qq.com

回复 Neil_HL:
请问如何设置这个呢?没有api
2019-05-21 16:48
454609449@qq.com

454609449@qq.com

css变量var(--status-bar-height)和js获取到uni.getSystemInfoSync().statusBarHeight的高度不一样,前者是25px,后者是20px
另,能否详细说明下导航的参数,如高度、字体颜色大小等等,为了多端保持样式统一,不然用了原生导航和自定义导航的页面会发生不一样啊啊啊啊
2019-05-17 14:26
903961766@qq.com

903961766@qq.com

回复 angelporthome@gmail.com:
使用自定义导航栏时,胶囊按钮遮挡住了导航栏右边的按钮,这个怎么处理呢
2019-05-16 23:34
798716565@qq.com

798716565@qq.com

回复 915105421@qq.com:
我也发现不生效。
可解决了
2019-05-14 19:15
EJ

EJ

动态设置标题栏的type,当type为transparent时,标题栏同时显示了上个页面的标题栏,所以看上去就没有了透明的效果,请问是bug吗
2019-05-08 12:14
1845113886@qq.com

1845113886@qq.com

取消原生导航栏之后,横屏状态下无法获取导航栏高度
2019-05-06 15:15
angelporthome@gmail.com

angelporthome@gmail.com

胶囊实现 https://blog.csdn.net/nicepainkiller/article/details/88993041
2019-04-29 11:21
915105421@qq.com

915105421@qq.com

回复 915105421@qq.com:
已解决,page.json中的searchInput中disabled设置为true,我当时设置的false,所以总是点击出现键盘,而不执行事件
2019-04-12 14:36
915105421@qq.com

915105421@qq.com

在pages.json中设置搜索框,当时在页面生命周期设置onNavigationBarSearchInputClicked()点击搜索框时不生效,各路大神,在线等。。。
2019-04-12 12:46
zjprevenge@126.com

zjprevenge@126.com

采用weex自定义导航栏,测试手机上首次加载时会出现闪动,主要是因为statusBarheight最开始没有值,等获取到statusBarheight的值才会把导航栏给挤下来,这个问题该怎么解决,我是参考http://ask.dcloud.net.cn/article/35111这个做的
2019-04-12 11:08
wander_jiyi@163.com

wander_jiyi@163.com

回复 我吃柠檬:
uni.setNavigationBarTitle,这个方法,官方的API
2019-04-10 10:43
Javin

Javin

回复 鸟鸟:
使用 redirectTo 来跳转页面
2019-04-07 18:37
我吃柠檬

我吃柠檬

怎么在页面中动态修改 navigationBarTitleText 的值
2019-04-04 10:16
1174762990@qq.com

1174762990@qq.com

padding-top: calc(var(--status-bar-height) + 80px); 网页版 会直接显示0
2019-03-28 20:32
804466860@qq.com

804466860@qq.com

回复 uljfidri@foxmail.com:
可以看下这个https://segmentfault.com/a/1190000017534998
2019-03-25 13:34
扶摇侠客

扶摇侠客

感谢,收下了
2019-03-16 21:16
361801580@qq.com

361801580@qq.com

2019-03-15 18:58
Neil_HL

Neil_HL (作者)

回复 鸟鸟:
首页有返回箭头你不会绝得很怪异吗?
2019-03-11 13:17
342301483@qq.com

342301483@qq.com

会用到,谢谢!
2019-03-10 10:09
shanjixiaboss@163.com

shanjixiaboss@163.com

码下,感觉后面会用到
2019-02-19 16:32
鸟鸟

鸟鸟

回复 Neil_HL:
通过看hello uni-app例子发现,只要是应用启动页(pages数组中第一项),导航栏都会自动隐藏后退按钮。这个类似的设定能否开放出来?
2018-12-19 16:09
150560159@qq.com

150560159@qq.com

感谢,收下了
2018-12-13 21:34
鸟鸟

鸟鸟

有办去掉原生导航的返回>不?
2018-12-11 11:28
Neil_HL

Neil_HL (作者)

回复 523200114@qq.com:
还不支持,如果是首页跳转的话,可以使用redirectTo进行跳转,就没有返回箭头了
2018-12-10 13:54
523200114@qq.com

523200114@qq.com

有办去掉原生导航的返回>不?
2018-12-07 17:42
Neil_HL

Neil_HL (作者)

回复 sampen:
app可以设置titleNview为false,可以针对单个页面取消
2018-12-06 19:49
sampen

sampen

取消原生导航栏只能全局设置吗?能不能针对单个页面取消?
2018-12-06 18:03
jsrdxzd@qq.com

jsrdxzd@qq.com

在干嘛呢各位大神
2018-11-12 12:30
1109693132@qq.com

1109693132@qq.com

回复 uljfidri@foxmail.com:
去百度字体编辑器打开.ttf这个文件你就知道了!
2018-10-27 17:28
三千烦恼丝瓜

三千烦恼丝瓜

方法2 安卓手机兼容问题,APP启动 首页上面有一条白色的。向上滑动 再滑回来就正常。ios 目前正常。
2018-10-10 10:15
DCloud_heavensoft

DCloud_heavensoft

回复 626045336@qq.com:
升级最新版HBuilderX,新建hello uni-app,模板里有自定义导航的源码
2018-09-18 16:28
626045336@qq.com

626045336@qq.com

用了这个源码,发现还是不行,还是出现在状态栏下方了。测试机荣耀6
2018-09-18 15:58
625467820@qq.com

625467820@qq.com

回复 DCloud_heavensoft:
恩,谢谢,更新了,已经生效
2018-09-17 18:45
DCloud_heavensoft

DCloud_heavensoft

回复 625467820@qq.com:
升级最新版
2018-09-17 17:12
625467820@qq.com

625467820@qq.com

回复 DCloud_heavensoft:
padding-top: calc(var(--status-bar-height) + 80px); CSS变量 获取状态栏高度在小程序有用。在安卓完全没效果
2018-09-17 16:41
DCloud_heavensoft

DCloud_heavensoft

回复 uljfidri@foxmail.com:
前面font设了src为某个字体,然后这个字体里内部规定了不同的字符显示成什么样,在/static/uni.ttf这个字体里,\ue534就会被显示为那个样子。0914版HBuilderX对预置title的buttons设置进行了简化,支持type: (String 类型 )按钮样式,可取值: "forward" - 前进按钮; "back" - 后退按钮; "share" - 分享按钮; "favorite" - 收藏按钮; "home" - 主页按钮; "menu" - 菜单按钮; "close" - 关闭按钮; "none" - 无样式。
2018-09-14 23:45
uljfidri@foxmail.com

uljfidri@foxmail.com

想知道 "text": "\ue534", 这个 \ue534 为什么是个图标,这个是怎么得来的,找了下网上的图标都是class或者是unicode符号,唯独找不到这种类型的,如果可以告诉我,谢谢
2018-09-14 22:21
工藤驼一

工藤驼一

回复 714252564@qq.com:
谢谢哈,我已经写了,新建一个自己的iconfont引入就好
2018-09-11 10:38
uniapp视频教程

uniapp视频教程

赞一个
2018-09-10 13:25
714252564@qq.com

714252564@qq.com

回复 工藤驼一:
有没有写在你的样式上面指定font-family
2018-09-10 10:02
瞳player

瞳player

回复 594zhulin@sina.com:
自定义组件的话使用xxx-header
2018-09-05 18:06
Neil_HL

Neil_HL (作者)

回复 工藤驼一:
navigationBarTextStyle设为black
2018-09-04 17:13
工藤驼一

工藤驼一

手机自带的状态显示是白色的,自己写的状态栏怎么改变其中wifi 电量等颜色?
2018-09-04 16:53
工藤驼一

工藤驼一

回复 xiazhaoweiii@126.com:
透明的状态栏怎么设置啊
2018-09-04 16:49
DCloud_heavensoft

DCloud_heavensoft

回复 wzl16:
有关注,就是收藏
2018-09-04 15:30
工藤驼一

工藤驼一

回复 Neil_HL:
请详细一点,我在icon.css和uni.css都引入了自己在阿里icon上下的ttf,static里也放了,可是没展示,是不是还缺什么
2018-09-04 14:57
Neil_HL

Neil_HL (作者)

回复 工藤驼一:
不支持绘制png,ttf得你自己放到工程里面(附件里没有方案二)。方案二还没开放,下个版本生效
2018-09-04 11:06
wzl16

wzl16

居然没有贴子收藏功能
2018-09-04 11:06
工藤驼一

工藤驼一

buttons里可以把ttf换成png吗,有这个属性吗?文档里说一下啊,ttf也没看到哪儿有
2018-09-04 11:00
594zhulin@sina.com

594zhulin@sina.com

组件命名有个bug,把title变为header会报错
2018-08-17 14:03
xiazhaoweiii@126.com

xiazhaoweiii@126.com

嗯,好主意完全可以自定义,但是HbuildX在MAC下发热严重,希望改善
2018-08-16 15:42