UPDATE 2022/11/27

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

<!-- 假如这是页面标题 -->
<view class="title" style="margin-top:{{胶囊距离顶部的高度}};height:{{胶囊自身高度}}px"></view>

/* 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

已有 2 条评论

  1. 111

    使用rect.top 更加精准

    1. 这篇文章已经过时了,当时是第一次做,弄复杂了,现在很容易就做出来……

添加新评论