专注小程序 / APP 开发,用代码改变生活

获取方案
全国分站 主站首页 北京分站 石家庄分站 唐山分站 保定分站 廊坊分站 沧州分站 郑州分站

微信小程序自定义头部实战技巧

小程序开发 2026-10-21 0 阅读 0 点赞 原创

做微信小程序时,原生导航栏往往满足不了设计需求:首页要沉浸式背景图、详情页要透明渐变、品牌页要放 logo 和搜索框。这时就得用自定义头部(custom navigationBar)。我做过十几个带自定义头部的项目,把踩过的坑和可复用的写法整理成这篇,直接抄代码就能用。

一、先关掉原生导航栏

在页面 json 里配置:

{
  "navigationStyle": "custom",
  "disableScroll": false
}

注意 navigationStyle: custom 只在页面级生效,app.json 里配也可以全局生效。关闭后页面会从屏幕最顶部开始渲染,状态栏区域会被内容覆盖,所以必须自己算高度。

二、核心:算出状态栏和胶囊高度

自定义头部高度 = 状态栏高度 + 导航栏高度。导航栏高度要和右上角胶囊按钮对齐,微信提供了 getMenuButtonBoundingClientRect 接口:

// 建议封装在 utils/navbar.js
export function getNavBarInfo() {
  const sys = wx.getWindowInfo ? wx.getWindowInfo() : wx.getSystemInfoSync()
  const statusBarHeight = sys.statusBarHeight || 20
  let navBarHeight = 44
  let statusBarGap = 4
  try {
    const menu = wx.getMenuButtonBoundingClientRect()
    // 胶囊上下间距一致,导航栏高度 = 胶囊高度 + 上下间距
    navBarHeight = (menu.top - statusBarHeight) * 2 + menu.height
    statusBarGap = menu.top - statusBarHeight
  } catch (e) {
    // 极少数基础库不支持,走兜底值
  }
  return {
    statusBarHeight,
    navBarHeight,
    totalHeight: statusBarHeight + navBarHeight,
    menuLeft: sys.windowWidth - 10 - 87 // 胶囊左侧大致位置,用于避让
  }
}

几个关键点:

  • 优先用 wx.getWindowInfo(),getSystemInfoSync 已被标记为不推荐,新项目别再用了。
  • 导航栏高度不要写死 44,iPhone 和部分安卓机型胶囊位置不同,用胶囊反推最稳。
  • 计算要在 onLoad 里做一次缓存到 data,别放在渲染函数里反复调用。

三、组件化写法

把头部抽成自定义组件,页面里传标题和返回逻辑:

// components/nav-bar/index.js
Component({
  properties: {
    title: { type: String, value: '' },
    bgColor: { type: String, value: '#ffffff' },
    showBack: { type: Boolean, value: true }
  },
  data: { statusBarHeight: 20, navBarHeight: 44 },
  lifetimes: {
    attached() {
      const sys = wx.getWindowInfo()
      const menu = wx.getMenuButtonBoundingClientRect()
      const statusBarHeight = sys.statusBarHeight
      this.setData({
        statusBarHeight,
        navBarHeight: (menu.top - statusBarHeight) * 2 + menu.height
      })
    }
  },
  methods: {
    onBack() {
      const pages = getCurrentPages()
      if (pages.length > 1) {
        wx.navigateBack()
      } else {
        wx.reLaunch({ url: '/pages/index/index' })
      }
    }
  }
})
<!-- components/nav-bar/index.wxml -->
<view class="nav" style="height:{{statusBarHeight + navBarHeight}}px;background:{{bgColor}}">
  <view style="height:{{statusBarHeight}}px"></view>
  <view class="nav-bar" style="height:{{navBarHeight}}px">
    <view wx:if="{{showBack}}" class="back" bindtap="onBack">‹</view>
    <view class="title">{{title}}</view>
  </view>
</view>
<!-- 占位,避免页面内容被头部盖住 -->
<view style="height:{{statusBarHeight + navBarHeight}}px"></view>

注意标题要居中但又要避开胶囊,通常给标题容器加 padding: 0 100rpx 左右,或者直接用绝对定位 + left: 0; right: 0; text-align: center,再靠 pointer-events: none 防止挡住右侧操作区。

四、沉浸式与滚动渐变

首页想要背景图铺满状态栏,做法是头部 position: fixed,背景透明,页面顶部放一张图。滚动时监听 onPageScroll 动态改透明度:

onPageScroll(e) {
  const opacity = Math.min(e.scrollTop / 100, 1)
  if (Math.abs(opacity - this.data.navOpacity) > 0.02) {
    this.setData({ navOpacity: opacity })
  }
}

这里一定要做阈值判断,否则每帧都 setData 会明显卡顿。另外页面滚动时头部文字颜色也要跟着从白变黑,用两套 class 切换即可。

五、几个容易踩的坑

  • 下拉刷新:自定义头部下,下拉刷新的 loading 会从顶部出现,和头部重叠。可以在页面 json 里开 "enablePullDownRefresh": true 后配合 backgroundTextStyle 处理,或者干脆用 scroll-view 自己做下拉。
  • 返回按钮热区:返回箭头别只给 20rpx 宽,热区至少 88rpx × 88rpx,否则用户点不中。
  • 分享卡片和页面栈:从分享进入时页面栈只有一页,navigateBack 会失败,必须兜底 reLaunch 到首页,上面组件代码已经处理。
  • 深色模式:如果项目支持 darkmode,头部背景色要跟随 theme 变化,别写死白色。

自定义头部本身不难,难的是把高度计算、返回兜底、滚动性能这几处细节一次性做对。把上面的组件放进项目里,后面每个页面传个 title 就能用,省下的时间够你多写两个业务页面了。

选对app制作工具,少走弯路微信小程序自定义tabbar实战

评论 (0)

还没有评论,快来抢沙发吧~

好想法,值得被认真交付

从小程序、APP 到全栈网站,一站式把想法变成可落地的产品

微信咨询

微信扫码,直接沟通需求