详解⼩程序胶囊按钮返回⾸页⾃定义导航栏功能
对于⼀些电商平台来说,当商品被转发后会很影响客户查看其它产品和⾸页,这时候就需要使⽤⾃定义导航栏⾃⼰写⼀个“胶囊按钮”。这篇⽂章主要介绍了详见⼩程序胶囊按钮返回|⾸页⾃定义导航栏,需要的朋友可以参考下
在⼩程序中,从转发出来的⼩程序消息卡⽚进⼊,因为页⾯栈中只有⼀个,所以不会出现返回按钮,对于⼀些电商平台来说,当商品被转发后会很影响客户查看其它产品和⾸页,这时候就需要使⽤⾃定义导航栏⾃⼰写⼀个“胶囊按钮”。如下图所⽰:
从别的页⾯点到商品页时会有返回和⾸页按钮;
当从分享页进⼊到商品页时,因为页⾯栈只有⼀个,所以只有⾸页按钮;
⾸先我们需要如何开启⾃定义导航栏,查看⼿册后会发现⼀个页⾯配置项: navigationStyle
之前的版本此配置项只能在app.js中配置,是全局的属性,⽽现在可以在单独的页⾯json中配置,实现单独页⾯⾃定义导航栏。
整体思路
当使⽤了 navigationStyle:custom 后,之前的顶部标题栏会被删除,右侧的胶囊按钮则会固定在右上⾓。然后在当前页⾯添加了三个
view(状态栏、标题栏、主体内容),可以看出三块的布局,我直接写死的⾼度:状态栏20px,标题栏44px。这个是⾃定义导航栏的关键,需要去计算这两块的⾼度,还有返回|⾸页胶囊按钮的位置。基础库 2.1.0开始可以使⽤ wx.getMenuButtonBoundingClientRect() 来获得 右侧胶囊按钮的位置信息 ,⽽有了这个信息,就能相对的算出我们想要在左侧添加的胶囊按钮的位置。通过 wx.getSystemInfoSync()中的statusBarHeight到状态栏的⾼度 。
⽬录结构
<span ><span >├── 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</span></span>
全局变量
app.js
在app.js中要先获得状态栏⾼度和右侧胶囊位置信息
<span ><span >App({
onLaunch: function (options) {
// 这⾥省略掉了登录和获取⽤户信息等函数
/
/ 因为我在别的页⾯也需要使⽤此信息,所以没有单独获得 statusBarHeight
success: (res) => {
this.globalData.systeminfo = res
},
})
// 获得胶囊按钮位置信息
this.globalData.headerBtnPosi = wx.getMenuButtonBoundingClientRect()
},
globalData: {
systeminfo: {}, // 系统信息
headerBtnPosi: {} // 胶囊按钮位置信息
}
})</span></span>
这⾥需要注意wx.getMenuButtonBoundingClientRect(),并不是像wx.getSystmInfo⼀样有success回调函数,⽽是像对象⼀
样 wx.getMenuButtonBoundingClientRect().height来使⽤。
组件代码
headerNavbar.wxml
<span ><span ><!-- ⾃定义导航栏 -->
<view class='navbar-wrap'
style='height:{{navbarHeight}}px;padding-top:{{statusBarHeight}}px;'>
<view class="navbar-text"
style='line-height:{{navbarBtn.height + p}}px;'>
{{navbarData.title ? navbarData.title : "默认标题"}}{{navbarHeight}}
</view>
<view class="navbar-icon"
wx:if='{{navbarData.showCapsule ? navbarData.showCapsule : true}}'
>
<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></span></span>
为了适配不同⼿机屏幕, ⾼度和胶囊按钮的位置都需要在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*/
现胶囊上边距 = 胶囊上边界坐标 - 状态栏⾼度
现胶囊右边距 = 屏幕宽度 - 胶囊右边界坐标
现胶囊下边距 = 胶囊下边界坐标 - 胶囊⾼度 - 状态栏⾼度
导航栏⾼度 = 胶囊下边界坐标 + 现胶囊下边距
注意:胶囊下边界坐标包含了 状态栏、胶囊⾼度和状态栏和胶囊⾼度之间的距离,因为胶囊是居中在导航栏⾥的 ,所以上边距与下边距应该⼀致,所以是 胶囊下边界坐标 - 胶囊⾼度 - 状态栏⾼度。
<span ><span >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: p - 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',
});
}
}
})</span></span>
通过 getCurrentPages()来判断当前页⾯是否从分享页进⼊, 因为如果从分享页进⼊页⾯栈中应该只有⼀条数据,在跳转到其他页⾯时页⾯栈的length则会增加 ,在其他页⾯就会显⽰出返回和⾸页按钮。
注意:7.0.0⽀持wx.getMenuButtonBoundingClientRect(),如果想兼容低版本的,只能把导航栏的⾼度写死,通过⼀些⼤佬的计算得出的⾼度:
'iPhone': 64,
'iPhone X': 88,
'android': 68
具体查看:
如果你使⽤ wx.getMenuButtonBoundingClientRect()得到信息有⼩数 ,如下所⽰
{height: 24, width: 65.25, top: -0.5, bottom: -0.5, right: 101.25}
那么你可能是把开发⼯具中的视图缩放了,还原成100%就正常了。
headerNavbar.wxss
<span ><span >.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;
}
</span></span>
引⽤组件页⾯代码
navigationStyle.json
<span ><span >{
"navigationStyle": "custom",
"enablePullDownRefresh": true,
"backgroundTextStyle": "light",
"usingComponents": {
"headerNavbar": "/components/headerNavbar/headerNavbar"
}
}</span></span>
先在需要使⽤⾃定义导航栏的页⾯json中添加navigationStyle:custom enablePullDownRefresh: true 开启下拉刷新
backgroundTextStyle: light是把loading的样式改成⽩⾊,这样就不会显⽰出来loading的三个点navigationStyle.wxml