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


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 相关文章推荐
List Information About the Binary Files Used by an Application
Jun 18 Javascript
javascript history对象(历史记录)使用方法(实现浏览器前进后退)
Jan 07 Javascript
js控制分页打印、打印分页示例
Feb 08 Javascript
JavaScript数组Array对象增加和删除元素方法总结
Jan 20 Javascript
js实现完美兼容各大浏览器的人民币大小写相互转换
Oct 29 Javascript
js原型链与继承解析(初体验)
May 09 Javascript
JSONP原理及简单实现
Jun 08 Javascript
简单理解vue中实例属性vm.$els
Dec 01 Javascript
vue组件间通信解析
Mar 01 Javascript
EasyUI为Numberbox添加blur事件的方法
Mar 05 Javascript
详解vue 单页应用(spa)前端路由实现原理
Apr 04 Javascript
Vue 框架之键盘事件、健值修饰符、双向数据绑定
Nov 14 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之第三天
2006/10/09 PHP
Jquery+JSon 无刷新分页实现代码
2010/04/01 Javascript
浅析JavaScript中两种类型的全局对象/函数
2013/12/05 Javascript
js 高效去除数组重复元素示例代码
2013/12/19 Javascript
创建你的第一个AngularJS应用的方法
2015/06/16 Javascript
jQuery实用技巧必备(下)
2015/11/03 Javascript
jquery原理以及学习技巧介绍
2015/11/11 Javascript
jQuery中判断对象是否存在的方法汇总
2016/02/24 Javascript
jQuery的ajax下载blob文件
2016/07/21 Javascript
基于Bootstrap的Java开发问题汇总(Spring MVC)
2017/01/15 Javascript
js实现简单的二级联动效果
2017/03/09 Javascript
JavaScript中splice与slice的区别
2017/05/09 Javascript
js的继承方法小结(prototype、call、apply)(推荐)
2019/04/17 Javascript
详解如何提升JSON.stringify()的性能
2019/06/12 Javascript
在vue中使用防抖和节流,防止重复点击或重复上拉加载实例
2019/11/13 Javascript
微信小程序pinker组件使用实现自动相减日期
2020/05/07 Javascript
JS端基于download.js实现图片、视频时直接下载而不是打开预览
2020/05/09 Javascript
微信小程序自定义tabBar的踩坑实践记录
2020/11/06 Javascript
对python操作kafka写入json数据的简单demo分享
2018/12/27 Python
python selenium 查找隐藏元素 自动播放视频功能
2019/07/24 Python
python3实现mysql导出excel的方法
2019/07/31 Python
详细整理python 字符串(str)与列表(list)以及数组(array)之间的转换方法
2019/08/30 Python
如何理解python中数字列表
2020/05/29 Python
python 通过pip freeze、dowload打离线包及自动安装的过程详解(适用于保密的离线环境
2020/12/14 Python
用CSS3将你的设计带入下个高度
2009/08/08 HTML / CSS
英国舒适型鞋履品牌:FitFlop
2017/05/17 全球购物
阿玛尼美妆俄罗斯官网:Giorgio Armani Beauty RU
2020/07/19 全球购物
金融专业应届生求职信
2013/11/02 职场文书
《中国的气候》教学反思
2014/02/23 职场文书
行政专员的岗位职责
2014/03/10 职场文书
护理专科毕业自荐信范文
2014/04/21 职场文书
公司委托书怎么写
2014/08/02 职场文书
2015年数学教研工作总结
2015/07/22 职场文书
股东协议书范本2016
2016/03/21 职场文书
2019年行政人事个人工作总结范本!
2019/07/19 职场文书
微信小程序scroll-view不能左右滑动问题的解决方法
2021/07/09 Javascript