详解微信小程序胶囊按钮返回|首页自定义导航栏功能


Posted in Javascript onJune 14, 2019

项目代码:https://github.com/Shay0921/header-navbar.git

在小程序中,从转发出来的小程序消息卡片进入,因为页面栈中只有一个,所以不会出现返回按钮,对于一些电商平台来说,当商品被转发后会很影响客户查看其它产品和首页,这时候就需要使用自定义导航栏自己写一个“胶囊按钮”。如下图所示:

从别的页面点到商品页时会有返回和首页按钮;

详解微信小程序胶囊按钮返回|首页自定义导航栏功能 

当从分享页进入到商品页时,因为页面栈只有一个,所以只有首页按钮;

详解微信小程序胶囊按钮返回|首页自定义导航栏功能 

首先我们需要如何开启自定义导航栏,查看手册后会发现一个页面配置项: navigationStyle

详解微信小程序胶囊按钮返回|首页自定义导航栏功能 

之前的版本此配置项只能在app.js中配置,是全局的属性,而现在可以在单独的页面json中配置,实现单独页面自定义导航栏。

整体思路

当使用了 navigationStyle:custom 后,之前的顶部标题栏会被删除,右侧的胶囊按钮则会固定在右上角。然后在当前页面添加了三个view(状态栏、标题栏、主体内容),可以看出三块的布局,我直接写死的高度:状态栏20px,标题栏44px。这个是自定义导航栏的关键,需要去计算这两块的高度,还有返回|首页胶囊按钮的位置。基础库 2.1.0开始可以使用 wx.getMenuButtonBoundingClientRect() 来获得 右侧胶囊按钮的位置信息 ,而有了这个信息,就能相对的算出我们想要在左侧添加的胶囊按钮的位置。通过 wx.getSystemInfoSync()中的statusBarHeight找到状态栏的高度 。

详解微信小程序胶囊按钮返回|首页自定义导航栏功能 

目录结构

├── components     组件
│ ├── headerNavbar    顶部自定义导航栏
│ │ └── headerNavbar.js
│ │ └── headerNavbar.json
│ │ └── headerNavbar.wxml
│ │ └── headerNavbar.wxss
├── pages      页面
│ ├── index     首页
│ │ └── index.js
│ │ └── index.json
│ │ └── index.wxml
│ │ └── index.wxss
│ ├── navigationStyle   引入自定义导航栏的页面(单独配置了navigationStyle)
│ │ └── navigationStyle.js
│ │ └── navigationStyle.json
│ │ └── navigationStyle.wxml
│ │ └── navigationStyle.wxss
│ │ └── testPage.js   路由测试页面(后面用来测试跳转显示不同胶囊按钮)
│ │ └── testPage.json
│ │ └── testPage.wxml
│ │ └── testPage.wxss

全局变量

app.js

在app.js中要先获得状态栏高度和右侧胶囊位置信息

App({
 onLaunch: function (options) {
  // 这里省略掉了登录和获取用户信息等函数
  // 因为我在别的页面也需要使用此信息,所以没有单独获得 statusBarHeight
  wx.getSystemInfo({ // 获取设备信息
  success: (res) => {
   this.globalData.systeminfo = res
  },
  })
  // 获得胶囊按钮位置信息
  this.globalData.headerBtnPosi = wx.getMenuButtonBoundingClientRect()
 },
 globalData: {
  systeminfo: {}, // 系统信息
  headerBtnPosi: {} // 胶囊按钮位置信息
 }
})

这里需要注意wx.getMenuButtonBoundingClientRect(),并不是像wx.getSystmInfo一样有success回调函数,而是像对象一样 wx.getMenuButtonBoundingClientRect().height 来使用。

组件代码

headerNavbar.wxml

<!-- 自定义导航栏 -->
<view class='navbar-wrap' 
 style='height:{{navbarHeight}}px;padding-top:{{statusBarHeight}}px;'> 
 <view class="navbar-text"
 style='line-height:{{navbarBtn.height + navbarBtn.top}}px;'>
 {{navbarData.title ? navbarData.title : "默认标题"}}{{navbarHeight}}
 </view>
 <view class="navbar-icon"
 wx:if='{{navbarData.showCapsule ? navbarData.showCapsule : true}}'
 style="top:{{navbarBtn.top + statusBarHeight}}px;left:{{navbarBtn.right}}px;height:{{navbarBtn.height}}px;"> 
  <image wx:if='{{haveBack}}' bindtap="_goBack" class="floatL" src="/img/navbar_back_white.png"></image>  
  <view wx:if='{{haveBack}}' class="floatL"></view>
  <image bindtap="_goHome" src="/img/navbar_home_white.png"></image>
 </view>
</view>
<!-- 手写loading -->
<view class="navbar-loading" style='height:{{navbarHeight}}px;line-height:{{navbarHeight}}px;'>
 <text>...</text>
</view>

为了适配不同手机屏幕, 高度和胶囊按钮的位置都需要在html里面赋值 ,下面会详细的说明高度如何计算。在自定义导航栏组件中分为两部分, 一个是顶部的导航栏另一个是自己写的loading。

因为自定义导航栏是fixed到顶部的, 为了保证不挡住下面的主体内容,我们需要在导航栏和主体内容之间添加一个跟导航栏相同的高度 ,class先叫做box。这样可以保证导航栏不挡着主体内容。但是会出现另一个问题,如果此页面支持下拉刷新, 那么导航栏会把小程序原生的loading样式挡住,而在主体内容的前面会出现一个空白的box,虽说不影响使用,但是在用户看来会很奇怪,莫名其妙的多出来一块,box只有在loading结束后才会上去 。所以在这里需要自己手写一个loading的动画效果放在组件的最底下,高度跟导航栏一样。

可以看到下面的最终效果,蓝色导航条下面的三个点是小程序原生loading,再下面三个小点是自己写的loading。

详解微信小程序胶囊按钮返回|首页自定义导航栏功能 

而我们想要的效果则是,当小程序原生的loading被当时,自己写的loading就可以替代原生的loading

详解微信小程序胶囊按钮返回|首页自定义导航栏功能 

headerNavbar.js

状态栏高度 = app.globalData.systeminfo.statusBarHeight

需要注意 胶囊位置信息的原点是在页面的左上角 ,所以需要转换一下,把 原胶囊位置信息起名为胶囊,转换后的叫做现胶囊。

/*** iphone6 的胶囊位置信息
* wx.getMenuButtonBoundingClientRect() 坐标信息以屏幕左上角为原点
* 胶囊宽度: 87
* 胶囊高度: 32
* 胶囊左边界坐标: 278
* 胶囊上边界坐标: 26
* 胶囊右边界坐标: 365
* 胶囊下边界坐标: 58
* 状态栏高度:20*/

现胶囊上边距 = 胶囊上边界坐标 - 状态栏高度

现胶囊右边距 = 屏幕宽度 - 胶囊右边界坐标

现胶囊下边距 = 胶囊下边界坐标 - 胶囊高度 - 状态栏高度

导航栏高度 = 胶囊下边界坐标 + 现胶囊下边距

注意:胶囊下边界坐标包含了 状态栏、胶囊高度和状态栏和胶囊高度之间的距离,因为胶囊是居中在导航栏里的 ,所以上边距与下边距应该一致,所以是 胶囊下边界坐标 - 胶囊高度 - 状态栏高度。

const app = getApp();
Component({
 properties: {
 navbarData: { // 由父页面传递的数据
  type: Object,
  value: {},
  observer: function (newVal, oldVal) { }
 }
 },
 data: {
 haveBack: true, // 是否有返回按钮,true 有 false 没有 若从分享页进入则为 false
 statusBarHeight: 0, // 状态栏高度
 navbarHeight: 0, // 顶部导航栏高度
 navbarBtn: { // 胶囊位置信息
  height: 0,
  width: 0,
  top: 0,
  bottom: 0,
  right: 0
 }
 },
 // 微信7.0.0支持wx.getMenuButtonBoundingClientRect()获得胶囊按钮高度
 attached: function () {
 let statusBarHeight = app.globalData.systeminfo.statusBarHeight // 状态栏高度
 let headerPosi = app.globalData.headerBtnPosi // 胶囊位置信息
 /**
  * wx.getMenuButtonBoundingClientRect() 坐标信息以屏幕左上角为原点
  * 菜单按键宽度: 87
  * 菜单按键高度: 32
  * 菜单按键左边界坐标: 278
  * 菜单按键上边界坐标: 26
  * 菜单按键右边界坐标: 365
  * 菜单按键下边界坐标: 58
  */
 let btnPosi = { // 胶囊实际位置,坐标信息不是左上角原点
  height: headerPosi.height,
  width: headerPosi.width,
  // 胶囊top - 状态栏高度
  top: headerPosi.top - statusBarHeight,
  // 胶囊bottom - 胶囊height - 状态栏height (现胶囊bottom 为距离导航栏底部的长度)
  bottom: headerPosi.bottom - headerPosi.height - statusBarHeight,
  // 屏幕宽度 - 胶囊right
  right: app.globalData.systeminfo.screenWidth - headerPosi.right
 }
 let haveBack;
 if (getCurrentPages().length === 1) { // 当只有一个页面时
  haveBack = false;
 } else {
  haveBack = true;
 }
 this.setData({
  haveBack: haveBack, // 获取是否是通过分享进入的小程序
  statusBarHeight: statusBarHeight,
  navbarHeight: headerPosi.bottom + btnPosi.bottom, // 原胶囊bottom + 现胶囊bottom
  navbarBtn: btnPosi
 })
 },
 methods: {
 _goBack: function () {
  wx.navigateBack({
  delta: 1
  });
 },
 _goHome: function () {
  wx.switchTab({
  url: '/pages/index/index',
  });
 }
 }
})

通过 getCurrentPages() 来判断当前页面是否从分享页进入, 因为如果从分享页进入页面栈中应该只有一条数据,在跳转到其他页面时页面栈的length则会增加 ,在其他页面就会显示出返回和首页按钮。

注意:微信7.0.0支持wx.getMenuButtonBoundingClientRect(),如果想兼容低版本的微信,只能把导航栏的高度写死,通过一些大佬的计算得出的高度:

'iPhone': 64,

'iPhone X': 88,

'android': 68

具体查看:

https://developers.weixin.qq.com/community/develop/doc/0006c012dc8028f04b070dd0551004

如果你使用 wx.getMenuButtonBoundingClientRect()得到信息有小数 ,如下所示

{height: 24, width: 65.25, top: -0.5, bottom: -0.5, right: 101.25}

那么你可能是把开发工具中的视图缩放了,还原成100%就正常了。

详解微信小程序胶囊按钮返回|首页自定义导航栏功能 

headerNavbar.wxss

.navbar-wrap {
 position: fixed;
 width: 100%;
 top: 0;
 z-index: 9999999;
 background-color: #3281FF;
 box-sizing: border-box;
}
.navbar-text {
 text-align: center;
 font-size: 36rpx;
 color: #fff;
 font-weight: 600;
}
.navbar-icon {
 position: fixed;
 display: flex;
 border-radius: 64rpx;
 border: 0.5px solid rgba(255,255,255, 0.3);
 box-sizing: border-box;
}
.navbar-icon image {
 height: 20px;
 width: 20px;
 padding: 5px 10px 10px;
 display: inline-block;
 overflow: hidden;
}
.navbar-icon view {
 height: 18px;
 border-left: 0.5px solid rgba(255,255,255, 0.3);
 margin-top: 6px;
}
.navbar-loading {
 background: #fff;
 text-align: center;
}

引用组件页面代码

navigationStyle.json

{
 "navigationStyle": "custom", 
 "enablePullDownRefresh": true, 
 "backgroundTextStyle": "light", 
 "usingComponents": {
  "headerNavbar": "/components/headerNavbar/headerNavbar"
 }
}

先在需要使用自定义导航栏的页面json中添加navigationStyle:custom

enablePullDownRefresh: true 开启下拉刷新

backgroundTextStyle: light是把loading的样式改成白色,这样就不会显示出来loading的三个点

navigationStyle.wxml

<headernavbar navbar-data="{{nvabarData}}"></headernavbar> 
<view class="home-page"> 
 <text>
 上面是自定义导航栏↑↑↑
 </text> 
 <text>
 下面是主体内容↓↓↓
 </text> 
 <navigator url="./testPage">
 跳转到测试页
 </navigator> 
</view>

navigationStyle.js

Page({
 data: {
  // 组件所需的参数
  nvabarData: {
   showCapsule: 1,
   // 是否显示左上角胶囊按钮 1 显示 0 不显示
   title: '组件列表' // 导航栏 中间的标题
  }
 },
 onPullDownRefresh() {
  setTimeout(() = >{
   wx.stopPullDownRefresh(); // 停止下拉
  },
  2000);
 },
})

注意:虽说这么做在小程序开发工具中看起来都是对的,得到的导航栏高度也是64px但是在真机上测试后,还是有偏差,在iphone8 plus上高度是60px。

详解微信小程序胶囊按钮返回|首页自定义导航栏功能

可以通过这张图明显看到差了几px,如果你是单独几个页面使用自定义导航,细心的用户可能会发现,但是基本不影响。如果是全局使用自定义导航,那就不存在这个问题了。

项目代码:https://github.com/Shay0921/header-navbar.git

总结

以上所述是小编给大家介绍的详解微信小程序胶囊按钮返回|首页自定义导航栏功能,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

Javascript 相关文章推荐
JS是否可以跨文件同时控制多个iframe页面的应用技巧
Dec 16 Javascript
为jquery.ui.dialog 增加“自动记住关闭时的位置”的功能
Nov 24 Javascript
查看图片(前进后退)功能实现js代码
Apr 24 Javascript
Javascript闭包用法实例分析
Jan 23 Javascript
微信小程序 http请求详细介绍
Oct 09 Javascript
微信小程序 后台https域名绑定和免费的https证书申请详解
Nov 10 Javascript
Jquery Easyui选项卡组件Tab使用详解(10)
Dec 18 Javascript
详解微信小程序 登录获取unionid
Jun 27 Javascript
Vue中正确使用jQuery的方法
Oct 30 jQuery
详解express + mock让前后台并行开发
Jun 06 Javascript
Node.js Buffer模块功能及常用方法实例分析
Jan 05 Javascript
Vue插件之滑动验证码用法详解
Apr 05 Javascript
微信小程序版本自动更新的方法
Jun 14 #Javascript
vue+express+jwt持久化登录的方法
Jun 14 #Javascript
深入剖析JavaScript instanceof 运算符
Jun 14 #Javascript
ES6 Promise对象的含义和基本用法分析
Jun 14 #Javascript
ES6顶层对象、global对象实例分析
Jun 14 #Javascript
ES6数组与对象的解构赋值详解
Jun 14 #Javascript
简单了解Ajax表单序列化的实现方法
Jun 14 #Javascript
You might like
PHP strtotime函数详解
2009/12/18 PHP
PHP7 新特性详细介绍
2016/09/06 PHP
php mysql procedure实现获取多个结果集的方法【基于thinkPHP】
2016/11/09 PHP
laravel-admin的图片删除实例
2019/09/30 PHP
JQuery 浮动导航栏实现代码
2009/08/27 Javascript
3Z版基于jquery的图片复选框(asp.net+jquery)
2010/04/12 Javascript
js 获取坐标 通过JS得到当前焦点(鼠标)的坐标属性
2013/01/04 Javascript
js实现的常用的左侧导航效果
2013/10/17 Javascript
JQuery Highcharts 动态生成图表的方法
2013/11/15 Javascript
js闭包的用途详解
2014/11/09 Javascript
js实现图片从左往右渐变切换效果的方法
2015/02/06 Javascript
js实现鼠标点击文本框自动选中内容的方法
2015/08/20 Javascript
jquery悬浮提示框完整实例
2016/01/13 Javascript
快速掌握Node.js模块封装及使用
2016/03/21 Javascript
Angularjs 创建可复用组件实例代码
2016/10/09 Javascript
原生和jQuery的ajax用法详解
2017/01/23 Javascript
js date 格式化
2017/02/15 Javascript
基于Vue、Vuex、Vue-router实现的购物商城(原生切换动画)效果
2018/01/09 Javascript
javascript实现的字符串转换成数组操作示例
2019/06/13 Javascript
echarts实现获取datazoom的起始值(包括x轴和y轴)
2020/07/20 Javascript
收藏整理的一些Python常用方法和技巧
2015/05/18 Python
Python基于回溯法子集树模板解决数字组合问题实例
2017/09/02 Python
30秒轻松实现TensorFlow物体检测
2018/03/14 Python
使用python制作一个为hex文件增加版本号的脚本实例
2019/06/12 Python
pyqt5让图片自适应QLabel大小上以及移除已显示的图片方法
2019/06/21 Python
在PyCharm的 Terminal(终端)切换Python版本的方法
2019/08/02 Python
python 实现线程之间的通信示例
2020/02/14 Python
Python对称的二叉树多种思路实现方法
2020/02/28 Python
Python实现Canny及Hough算法代码实例解析
2020/08/06 Python
运动会广播稿300字
2014/01/10 职场文书
爱心捐书活动总结
2014/07/05 职场文书
社区综治工作汇报
2014/10/27 职场文书
2014年幼儿园后勤工作总结
2014/11/10 职场文书
先进党支部事迹材料
2014/12/24 职场文书
学生犯错保证书
2015/05/09 职场文书
DE1103使用报告
2022/04/05 无线电