一、默认导航栏
uni-app 默认会提供一个导航栏,即 小程序的导航栏 ,我们不需要进行任何的配置就会显示, 默认导航栏的配置同微信小程序 ,只不过微信小程序的组件是分为.wxml、.wxss、.js、.json 四个文件组成,而uni-app 的组件则只有一个.vue 文件(其中包含了 html、css、js),其中并未包含.json 的相关内容,那么.json 配置写在哪里呢?.json 文件主要是 对页面的 窗口表现及页面相关功能进行配置,所以 unip 在 pages.json 文件中注册页面的时候,给每个 page 页面提供了一个 style 属性,用于对当前页面的窗口表现 ( 窗口 样式、导航栏 样式)及功能 ( 页面下拉刷新 、 页面能否滚动 等),如:
{
"pages": [ //pages 数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": { // 对窗口及其页面表现进行配置
"navigationBarTitleText": "导航标题", // 设置默认导航栏标题文字内容
"navigationBarTextStyle": "white", // 设置默认导航栏标题文字颜色及状态栏上文字颜色,仅支持 black 和 white
"navigationBarBackgroundColor": "#4CD964", // 设置默认导航栏背景颜色及状态栏背景颜色,仅支持十六进制颜色值
"navigationStyle": "default", // 支持 defaul 和 custom 两种,设置 custom(自定义)后,默认导航栏将消失,微信小程序上只保持右上角胶囊按钮
"backgroundColor":"#ADFF2F", // 设置窗口背景颜色,开启下拉刷新之后,下拉后可见该背景颜色(黄色),仅小程序端生效
"enablePullDownRefresh": true, // 是否开启页面下拉刷新功能
// 上拉刷新不需要开启,页面提供了一个触底事件 onReachBottom,只要页面存在滚动条,滚动条触底后就可以触发触底事件,从而进行下拉刷新
"onReachBottomDistance": 0, // 当滚动条距离底部的距离为指定值的时候则判定为触底
"disableScroll": false, // 页面能否滚动,如果为 true 则禁用页面滚动功能,及时页面设置的高度超过了屏幕高度也不会发生滚动,仅小程序端生效
"usingComponents": { // 配置是否使用小程序提供的自定义组件,这里的小程序组件不是.vue 组件,而是小程序提供的原生组件,App 端也支持
"custom": "/wxcomponents/custom/index"
},
// "backgroundTextStyle":"dark", // 设置下拉 loading 的样式,仅支持 dark 和 light, 无明显用处
}
}
]
}
需要注意的就是 usingComponents 的配置,其配置的是使用 小程序提供的原生组件 (如包含.wxml、.wxss、.js、.json 的组件),而不是.vue 组件。同时 状态栏上文字颜色仅支持 black 和 white,即非黑即白,状态栏背景色同导航栏背景颜色
二、原生导航栏
uni-app 运行在 app 端的时候,还提供了原生导航栏,其在注册页面的时候,style 还提供了一个 app-plus 属性用于 配置 app 端 页面窗口、导航栏样式的配置,导航栏的配置通过 titleNView 属性,如:
{
"pages": [ //pages 数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": { // 对窗口及其页面表现进行配置
"app-plus": {
// "titleNView": false // 禁用原生导航栏,即当前页面不显示原生导航栏
"scrollIndicator":"none", // 设置是否显示页面滚动条,设置为 none,滚动时看不到右侧的滚动条
"pullToRefresh": {"style":"default" // 设置下拉刷新样式,只支持 default 和 circle},
"bounce":"none", // 设置页面回弹效果,none 关闭回弹效果
// "titleNView": { // 空对象不会对默认导航栏进行替换,必须进行相关配置才会对默认导航栏进行修改
// },
"titleNView": { // 对原生导航栏进行配置
"titleText": "原生导航栏标题内容", // 标题内容与搜索框只能显示一个
"buttons": [ // 在原生导航栏上添加按钮
{
// "type":"share", // 使用 type 值设置按钮的样式时,会忽略 fontSrc 和 text 属性。"fontSrc":"./static/font/icon.ttf", // 使用字体图标
"text": "\ue609", // 使用字体图标时 unicode 字符表示必须 '\u' 开头
"fontSize":"22px",
"color":"#FF9619",
"colorPressed":"#BBBBBB",
"select": false, // 是否显示右侧向下箭头图标常用于城市选择
"float":"left" // 按钮放在导航栏左侧
},
{
// "type":"favorite", // 使用 type 值设置按钮的样式时,会忽略 fontSrc 和 text 属性。"fontSrc":"./static/font/icon.ttf",
"text": "\ue653", // 使用字体图标时 unicode 字符表示必须 '\u' 开头
"fontSize":"22px",
"color":"#000000",
"colorPressed":"#BBBBBB",
"select": false, // 是否显示右侧向下箭头图标常用于城市选择
"float":"right" // 按钮放在导航栏右侧
}
],
"searchInput": { // 是否在原生导航栏上添加搜索框,一旦添加搜索框,那么导航栏标题内容将无法显示,因为搜索框是放在标题的位置,对标题进行了替换
"align":"center",
"backgroundColor":"#F7F7F7",
"borderRadius":"4px",
"placeholder":"搜索",
"disabled": true
}
}
}
}
}
]
}
三、自定义导航栏
要想自定义导航栏,我们必须先让默认导航栏或者原生导航栏隐藏,在小程序端可以通过 “navigationStyle”:”custom” 隐藏,app 端则可以通过 “titleNView”: false 进行隐藏,如:
{
"pages": [ //pages 数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path" : "pages/contact/contact",
"style" : {
"navigationStyle":"custom", // 隐藏小程序端导航栏
"app-plus": {"titleNView": false // 隐藏 app 端原生导航栏}
}
}
]
}
使用自定义导航栏导航后,由于默认导航栏和原生导航栏都消失了,所以原先导航栏的位置就被空出来了,我们可以 通过自定义一个导航视图组件占据原先导航栏的位置即可实现 ,但是下拉刷新会有问题,因为页面的下拉刷新是从顶部开始的,之前 有默认导航和原生导航的时候 , 页面的顶部就是导航栏底部 ,但是默认导航和原生导航隐藏后, 顶部就变成了原先导航栏的顶部了 ,所以 页面下拉刷新的位置向上移了 ,使用自定义导航栏后最好不要在页面中使用下拉刷新功能了。如果非要使用下拉刷新功能的话,我们可以通过 <scroll-view> 组件来模拟下拉刷新。即 监听 <scroll-view> 组件的 @scrolltoupper 事件判断是否到达顶部,然后监听 @scroll 事件,判断下拉的位置,然后动态改变下拉刷新的样式、动画 从而模拟出下拉刷新效果。
<view class="pull-down iconfont icon-liulan" :style="{transform:'rotate('+ detal+'deg)'}"></view>
<scroll-view scroll-y class="scroll-box" @scrolltoupper="pullDown" @scroll="scroll">
</scroll-view>
export default {
methods: {pullDown(e) {// console.log(e);
},
scroll(e) { // 根据下拉的距离改变 detal 的值从而改变下拉刷新图标的选择角度
this.detal = e.detail.scrollTop + 100;
}
}
}
四、vue 与 nvue
nvue 即 native vue。uni-app App 端内置 weex 渲染引擎,提供了原生渲染能力。uni-app 默认是处于 uni-app 的渲染模式,即小程序渲染模式,如果要启用纯原生渲染模式,即 weex 渲染模式,那么需要在manifest.json 源码视图的 “app-plus” 下配置“renderer”:”native”,开启原生渲染模式后,pages.json 注册的 vue 页面将被忽略,启动纯原生渲染,可以减少 App 端的包体积、加快 App 启动速度。因为 webview 渲染模式的相关模块将被移除了。
// manifest.json
{
// ...
/* App 平台特有配置 */
"app-plus": {"renderer": "native", //App 端纯原生渲染模式}
}
在未开启 weex 原生渲染模式的情况下,即 uni-app 模式下也是可以直接渲染.nvue 文件的,不管是 vue 页面还是 nvue 页面,都需要在 pages.json 中注册 ,并且如果一个页面下出现了两个同名的 vue 和 nvue 文件,那么在App 端, 会优先使用 nvue 页面 ,同名的 vue 文件将不会被编译到 App 端。而在 非 App 端 , 会优先使用 vue 页面。.nve 文件的写法同.vue 文件一样,只不过,.nvue 文件中可以还使用一些 weex 提供的特有组件,比如 <barcode>、<list>、<cell>、<refresh> 等。
五、subNvue
subNvue
,是vue
页面的原生子窗体,其会 把 weex 渲染的原生界面当做vue
页面的子窗体覆盖在页面上 ,主要解决 运行在 App 端时 , 视图无法覆盖在 <video>、<map> 等组件上 的问题 ( 非 App 端可以通过 z -index 或者 cover-view 解决 ),subNvue 的使用方式非常简单,只需要 新建一个.nvue 文件 ,建议放在母页面目录中,但是subNvue 页面不需要注册到 pages.json 中,而是 在母页的 ”style”–> “app-plus” –> “subNVues” 进行配置,因为 subNvue 主要解决 App 端层级覆盖问题,所以需要在 ”app-plus” 下配置,需要注意的是subNVues 是一个数组,每个元素为一个原生子窗体,因为一个母页中可以包含多个原生子窗体,每个原生子窗体通过配置中的 id 进行区分。配置好 subNvues 后,对应的原生子窗体默认就会显示。
{
"pages": [ //pages 数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path" : "pages/video/video", // 母页面路径
"style" : {
"navigationBarTextStyle":"white",
"app-plus": {
"titleNView":false,
"subNVues":[{
"id": "test", // 唯一标识,母页面中可以通过这个 id 调用 api 获取到原生子窗体
"path": "pages/video/subNVue/cover", // video 母页面下原生子窗体页面路径
// "type": "popup", // 这里不需要
"style": {
"position": "absolute",
// "dock":"right",
"width": "750rpx",
"height": "150upx", // 需要设置合适的高度,否则可能出现无法点击原生子窗体下面的内容
"background":"transparent" // 设置为透明,以便能看到原生子窗体下面的内容,如果有背景颜色,则全屏可见
}
}]
}
}
]
}
pages.json 文件中配置好原生子窗体后,不需要向 vue 组件一样引入到母页中,直接就会出现在母页面上,具体位置根据 subNVues 中的配置而定。
六、优化自定义导航栏下拉刷新功能
前面说过,使用自定义导航栏需要隐藏掉默认导航栏和原生导航栏,但是会存在一个问题,就是页面下拉刷新会跟着上移到了最顶部,导致页面下拉刷新位置不正确,之前的方法是使用 <scroll-view> 方法进行模拟,但是官方并不推荐该方法 ,我们可以通过原生子窗口实现,其实现方法非常简单,就是用原生子窗口占据原生导航栏的位置,其中关键的一步就是,在配置原生子窗体的时候, 需要将其 type 设置为 navigationBar 类型,该原生子窗体就会站住原生导航栏的位置,并且下拉刷新图标不会向上移,如:
{
"pages": [ //pages 数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path" : "pages/nav/nav",
"style" : {
"navigationBarTextStyle":"white",
"navigationBarBackgroundColor":"#007AFF",
"enablePullDownRefresh": true,
"app-plus": {
"titleNView": false,
"subNVues": [
{
"id":"nav",
"path":"pages/nav/subNvue/nav",
"type":"navigationBar" // 设置为 navigationBar 类型才能让原生子窗体站住原生导航栏的位置
}
]
}
}
},
]
}
pages/nav/subNvue/nav.nvue
<template>
<div class="nav">
<div class="status-bar"></div>
<div class="nav-title">
<div> 我是导航栏 </div>
</div>
</div>
</template>
<script>
export default { }
</script>
<style scoped>
.nav { /*.nvue 页面中的所有元素都是 flex 布局, 不需要进行显示设定 */
flex: 1; /* 占满整个导航栏高度, 当该原生子窗体页面被设置为 navigationBar 类型后, 会自动给予该页面一个导航高度, 占满即可 */
background-color: #007AFF;
}
.status-bar { /* 状态栏占位区, 下面导航标题栏已经设置了 44px 高度,让状态栏占满剩余高度 */
flex: 1;
}
.nav-title {
flex: 0;
height: 44px; /* 导航栏固定高度为 44px*/
background-color: #007AFF;
justify-content: center;
align-items: center;/* 导航栏标题区垂直居中显示 */
}
</style>
七、实现抽屉效果
所谓抽屉效果就是,就是页面上触发某种事件后,页面上方有一个页面从屏幕的一侧开始滑出覆盖到原来页面的上方,然后点击空白处,该页面又可以收回去的效果。要实现这种效果,我们也是需要利用原生子窗体,将抽屉页面做成一个原生子窗体覆盖在页面上方,其中关键的一步,就是 需要将其 type 设置为 popup 类型 , 设置为 popup 类型之后 , 该页面默认不会出现在母页面上,需要通过调用 api 才能让该抽屉页面显示出来。如:
{
"pages": [ //pages 数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path" : "pages/nav/nav",
"style" : {
"navigationBarTextStyle":"white",
"navigationBarBackgroundColor":"#007AFF",
"enablePullDownRefresh": true,
"app-plus": {
"titleNView": false,
"subNVues": [
{
"id":"drawer",
"path":"pages/nav/subNvue/drawer",
"type":"popup",
"style": {"width":"50%" // 只显示整个屏幕宽度的 50%, 高度默认为屏幕 100%}
}
]
}
}
},
]
}
pages/nav/subNvue/nav.nvue 母页通过 api 控制原生子窗体的显示和隐藏
<template>
<view>
母页面
<button @click="showDrawer"> 显示抽屉 </button>
</view>
</template>
<script>
export default {data() {return {}
},
methods: {showDrawer() {uni.getSubNVueById('drawer').show("slide-in-left", 200); // 从屏幕左侧向右边滑入,耗时 200ms
}
}
}
</script>
同样的方式也可以实现页面中间显示弹出框效果,只需要改变原生子窗体的位置即可,即将其定位到正中间,如:
{
"id":"drawer",
"path":"pages/nav/subNvue/drawer",
"type":"popup",
"style": {
"margin":"auto", // 居中显示
"height":"50%",
"width":"80%"
}
}