UPDATE 2022/11/27

这篇文章内容已经过时,不再具有参考意义。
实际上实现起来非常简单,只需要调用wx.getMenuButtonBoundingClientRect()方法获取胶囊的位置信息,再给相关的 wxml 节点加上合适的高度即可,例如:

/* wxss */
.title{
    display: flex;
    align-items: center;
}

以下是原内容

navigationStyle(官方文档)设置为custom后,导航栏消失,可以自定义导航栏。

在不同的手机上,胶囊到屏幕顶部的距离是不一样的,尤其是刘海屏,这个距离会很大。所以自定义导航栏的高度不能写死。页面主体部分不能被右上角的胶囊覆盖;为了美观,自定义导航栏的标题最好也和胶囊在水平上对齐。所以,自定义导航栏的高度需要适配。

思路很简单,获取胶囊的位置,让导航栏的高度等于胶囊底边到屏幕顶端的高度,记为h。另外,自定义导航栏的底边应该超出胶囊底边,目的是留一些空白,这样更加协调。所以,还要给h加上一个合适的数值。

翻阅了微信官方文档,没找到哪里规定了胶囊底边的留白高度。所以,我在iPhone 6S上找了一个小程序,截屏,手动量了一下胶囊底边到内容区域的高度为16px

胶囊底部留白高度

所以就定了留白高度是16px。其实这个高度可以根据自己的需要和审美来定。

但还有一个问题。16px是在宽度为750px的截图上测量的,因为iPhone 6S屏幕的物理像素是750px,所以截图就是750px。但在浏览器和小程序中,iPhone 6S逻辑宽度375,正好是750的一半。所以实际设置css高度的时候,16px也要除以2。其实这个2就是pixelRatio

我们以16为基准,除以设备的pixelRatio,就能得到实际的留白像素数。

注意:wx.getMenuButtonBoundingClientRect()等API返回的数值都是以px为单位的
所以上面讨论的都是px,要和rpx分清

下面是具体实现。

小程序运行过程中,屏幕参数是不会变的,所以,在小程序onLaunch中获取一次相关数据,然后存起来就行了:

app.js
...
onLaunch: function() {
if (wx.canIUse('getMenuButtonBoundingClientRect')) {
let sysInfo = wx.getSystemInfoSync();
let rect = wx.getMenuButtonBoundingClientRect();
let navBarHeight = rect.bottom + 16 / sysInfo.pixelRatio;
// 存储胶囊位置信息
wx.setStorageSync('menuButtonRect', rect);
// 存储自定义导航栏的高度
wx.setStorageSync('navBarHeight', navBarHeight);
} else {
wx.showToast({
title: '您的微信版本过低,界面可能会显示不正常',
icon: 'none',
duration: 4000
});
}
},
...

新建一个组件叫做nav

组件

组件navwxml

<view class="nav-box" style="height:{{height}}px">
  <view class="title">这是标题</view>
</view>

组件navjs

...
properties: {
  height: {
    type: Number,
    value: 80 // 默认值
  }
}
...


...
lifetimes: {
  attached() {
    this.setData({
      height: wx.getStorageSync('navBarHeight')
    })
  }
}
...

然后,页面只要引用这个nav组件就可以了。

现在nav组件已经可以正常适配绝大多数的设备了。受限于手头测试设备的限制,和微信接口的不稳定,可能有个别设备会适配失败。

这里只是适配了自定义导航栏的高度,其他的问题就不在本文讨论范围内了。

如果您有不同的看法或者任何意见,欢迎评论或者联系我。

End

标签: 微信小程序, navigationStyle