小程序自定义顶部导航栏

微信   2025-01-01 16:18   87   0  

前言

现成轮子网上很多,但是想实现自己的需求,还得自己再造一遍轮子,有一篇文章写的很好:微信小程序自定义navigationBar

效果图

29971_iojr_5907.png

亮点

  1. ✅保证安卓IOS显示效果一致

  2. 拓展🉑️同时显示返回上一页返回首页

  3. 点击标题🉑️返回顶部

  4. 预留slot进行拓展

index.js

Component({
  properties: {
    title: { // 标题
      type: String,
      value: 'hello world',
    },
    showGoBack: { // 显示返回按钮
      type: Boolean,
      value: false,
    },
    showHome: { // 显示返回主页按钮
      type: Boolean,
      value: false,
    },
    position: { // 是否开启绝对定位
      type: Boolean,
      value: false,
    },
    bgColor: { // 导航栏背景颜色
      type: String,
      value: 'transparent',
    },
    titleColor: { // 导航栏标题颜色
      type: String,
      value: '#000000',
    },
    showSlot: { // 是否开启slot
      type: Boolean,
      value: false,
    },
    showBlankBlock: { // 是否开启空白块占位
      type: Boolean,
      value: false,
    },
  },

  lifetimes: {
    async attached() {
      const systemInfo = await wx.getSystemInfo()

      const {
        statusBarHeight,
        windowWidth
      } = systemInfo

      const rightCapsule = wx.getMenuButtonBoundingClientRect()

      const {
        top,
        right,
        width,
        height
      } = rightCapsule

      const navBarYPadding = top - statusBarHeight

      const navBarXPadding = windowWidth - right

      const navBarHeight = height + (navBarYPadding * 2)

      const navBarBodyHeight = height

      const rightCapsuleWidth = width

      const styleData = `--bgColor: ${this.properties.bgColor};
        --statusBarHeight: ${statusBarHeight}px;
        --navBarHeight: ${navBarHeight}px;
        --navBarBodyHeight: ${navBarBodyHeight}px;
        --navBarYPadding: ${navBarYPadding}px;
        --navBarXPadding: ${navBarXPadding}px;
        --rightCapsuleWidth: ${rightCapsuleWidth}px;
        --rightCapsuleHeight: ${navBarBodyHeight}px;
        --rightCapsuleRadius: ${navBarBodyHeight / 2}px;
        --titleColor: ${this.properties.titleColor};
        `

      const backIconUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAY9JREFUWEfFl88rBVEUgL/3Lyj/lbLzI6UoSlGEKAsWihBFKUpRFspCSSkWxIJYKIqFYqFYkJWsJJ06V6ep9969c+e9O6upmeb7zo85c6ZE4qOUmE+tBBo0sM9qAdZCYAqYVHAXsFlJomiBaWDCAAUuEmWPIgVmgTFD+gWagMN6CMwDIwb0DbQD+/XogSVg0ICk8QR+VA0u12NLsAL0G9Ab0Aac+cBjBVaBPgN6VviVLzxGYB3oMaAHhd+GwPMKbADdBnQDtAKPofA8AltApwFdAi3ASx54qMA20GFApwp/zwsPEdjRNDuWDBeJ/CsG7iuwAAwb0J7Cf2LhvgKjwFxKAWEnLYELPtuEJ1qKj5hShI7i7Gt4oc1Zl9fQBZp0EDmJNaDXpP5eR/FdaDlCS2Cfn/0YPanEdYhEjIBwloEBA3xViXNfiVgB4SwCQwYoC4nsBMc+EkUICCfpSuYCnQHGTdSylDYDB5UyUVQGHCO7lu/qsCrrULSAgJL+mLhIG/Wk6q5Qiwz4NP//PckF/gCIUUwhlNMi4AAAAABJRU5ErkJggg=='

      const homeIconUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAidJREFUWEft10+oD1EUwPHPW2BlI5KdkiQ7C2+l2LDxr+SxIJSQEiURCyz0ZEFECPm78KdeSVYSKcXKBjslxYJkJRtJ53VH86aZ38xv3u+3+53Vnbn3nPO95557zsyQ9rIJuzAdj3GijamhNkrYjUsF3TM40K29NgCHMZocHcXf3PNV7OwGoluAUziUHOzD+TTeg4tpfA9b8KcJSDcAV3K724HrBQebcQ3T8CRB/KyDaAIwFXcwgt/YjvsVhtckiFl4mSA+d4KoA5iN21iB78l57K6TLMUNzMPbBPG+SqETwILkfAk+IUL8qi6kaX4h7mIxPibd12W6VQDDKezz8Q5x5yt3UQE1Ew+xDN8SxNPi2jKAlcl5nOMbrMeXhjsvW/YIkRuRPxHFsfyiIsDG5HwKnmEtfk3CeaYaSRzOQ7bhVjaRB4iyejlNBPW6HjjOmziL/enFXlyIcQYQxSWKTEjQBWU/5AhOJsMxHg2AVamZxPtzOcp+AITNKNVR1EJWB8BxHCvpZvG+l1K0N+4zACLcUTjy8gLLe+kdz9OVzJsdyXJgAxalmSDrJ0D23fAAH4rXMIpGkPYTICIb9selDUAc2daK44kbdLNiLjuCSQEcxOma3IgQlyVwTwDyRso4Oh1fTwHKekhd/gwABhEYRGAQgUYRmIEfNaW2qlHNwdcGLXxCESuraNFsoiXPLTEWzqPW/+9mhTXxfxitPb6oixJw8fM6oU/8A8+oq0Iv6rN4AAAAAElFTkSuQmCC'

      this.setData({
        statusBarHeight,
        navBarHeight,
        navBarBodyHeight,
        navBarYPadding,
        navBarXPadding,
        rightCapsuleWidth,
        styleData,
        backIconUrl,
        homeIconUrl,
      })
    },
  },

  data: {
    statusBarHeight: 20, // 状态栏高度
    navBarHeight: 40, // 导航栏高度
    navBarBodyHeight: 32, // 导航栏内容高度
    navBarYPadding: 4, // 导航栏Y轴内间距
    navBarXPadding: 8, // 导航栏X轴内间距
    rightCapsuleWidth: 87, // 右边胶囊宽度
    styleData: '', // 样式变量
    backIconUrl: '', // 返回icon
    homeIconUrl: '', // 主页icon
  },

  methods: {
    goBack() {
      // console.log('goBack');

      const pages = getCurrentPages()

      // 单曲页面栈小于等于一个页面,直接返回首页
      if (pages.length <= 1) {
        this.goHome()
      } else {
        wx.navigateBack()
      }
    },

    goHome() {
      // console.log('goHome');

      // 小程序中页面栈最多十层
      // 返回的页面数,如果 delta 大于现有页面数,则返回到首页。
      wx.navigateBack({
        delta: 10
      })
    },

    backTop() {
      wx.pageScrollTo({
        scrollTop: 0,
        duration: 300
      })
    },
  }
})


index.wxml

<view style="{{styleData}}">

  <view class="c-navbar {{position ? 'c-navbar--position' : ''}}">
    <!-- 状态栏 -->
    <view class="c-navbar__status-bar"></view>

    <!-- 导航栏 -->
    <view class="c-navbar__body" wx:if="{{!showSlot}}">
      <!-- 导航栏左边 => 胶囊 -->
      <view class="c-navbar__body__left">
        <view class="c-navbar__body__left__back" wx:if="{{showGoBack && (!showHome)}}" bindtap="goBack">
          <image src="{{backIconUrl}}" class="c-navbar__body__icon c-navbar__body__left__icon--back"></image>
          <text>返回</text>
        </view>

        <view class="c-navbar__body__left__home" wx:if="{{showGoBack && showHome}}">
          <view class="c-navbar__body__left__home__back" bindtap="goBack">
            <image src="{{backIconUrl}}" class="c-navbar__body__icon c-navbar__body__left__home--back"></image>
          </view>
          <view class="c-navbar__body__left__home--division"></view>
          <view class="c-navbar__body__left__home__home" bindtap="goHome">
            <image src="{{homeIconUrl}}" class="c-navbar__body__icon c-navbar__body__left__home--home"></image>
          </view>
        </view>
      </view>

      <!-- 导航栏中间 => 标题 -->
      <view class="c-navbar__body__title" bindtap="backTop">
        {{title}}
      </view>

      <!-- 导航栏右边 => 胶囊 -->
      <view class="c-navbar__body__right"></view>
    </view>

    <!-- 开启slot -->
    <view class="c-navbar__body" wx:if="{{showSlot}}">
      <view class="c-navbar__body--slot">
        <slot></slot>
      </view>

      <!-- 导航栏右边 => 胶囊 -->
      <view class="c-navbar__body__right"></view>
    </view>
  </view>

  <!-- 空白块占位符, 用于解决下拉刷新导航栏掉下来的问题, 需要配合开启position -->
  <view class="c-blank-block" wx:if="{{showBlankBlock}}"></view>
</view>


index.wxss

.c-navbar {
    position: -webkit-sticky;
    position: sticky;
    top: 0;
    left: 0;
    z-index: 9999;
    width: 100vw;
    box-sizing: border-box;

    background-color: var(--bgColor);
}

.c-navbar--position {
    position: fixed;
}

.c-navbar__status-bar {
    width: 100vw;
    height: var(--statusBarHeight);
}

.c-navbar__body {
    width: 100vw;
    height: var(--navBarHeight);
    padding: 0 var(--navBarXPadding);
    overflow: hidden;
    box-sizing: border-box;
    overflow: hidden;

    display: -webkit-flex;
    display: flex;
    /* -webkit-justify-content: center;
    justify-content: center; */
    -webkit-align-items: center;
    align-items: center;
    flex-wrap: wrap;
}

.c-navbar__body__left {
    width: var(--rightCapsuleWidth);
    height: var(--rightCapsuleHeight);
    box-sizing: border-box;
    font-size: 16px;
    font-weight: 500;

    display: -webkit-flex;
    display: flex;
    -webkit-justify-content: center;
    justify-content: center;
    -webkit-align-items: center;
    align-items: center;
    flex-wrap: wrap;
}

.c-navbar__body__title {
    box-sizing: border-box;
    flex: 1;
    padding: 0 var(--navBarXPadding);

    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;

    color: var(--titleColor);
    font-size: 18px;
    font-weight: 500;
}

.c-navbar__body__right {
    width: var(--rightCapsuleWidth);
    height: var(--rightCapsuleHeight);
}

.c-navbar__body__icon {
    display: inline-block;
    width: 20px;
    height: 20px;
}

.c-navbar__body__left__back {
    height: 100%;
    background-color: rgba(255, 255, 255, .6);
    border: 1px solid rgba(0, 0, 0, .1);
    border-radius: var(--rightCapsuleRadius);
    box-sizing: border-box;
    padding: 0 calc(var(--navBarXPadding) * 2);

    display: -webkit-flex;
    display: flex;
    -webkit-justify-content: center;
    justify-content: center;
    -webkit-align-items: center;
    align-items: center;
    flex-wrap: wrap;
}

.c-navbar__body__left__icon--back {
    margin-left: -5px;
}

.c-navbar__body__left__home {
    position: relative;

    width: 100%;
    height: 100%;
    background-color: rgba(255, 255, 255, .6);
    border: 1px solid rgba(0, 0, 0, .1);
    border-radius: var(--rightCapsuleRadius);
    box-sizing: border-box;

    display: -webkit-flex;
    display: flex;
}

.c-navbar__body__left__home__back {
    flex: 1;

    display: -webkit-flex;
    display: flex;
    -webkit-justify-content: center;
    justify-content: center;
    -webkit-align-items: center;
    align-items: center;
    flex-wrap: wrap;
}

.c-navbar__body__left__home__home {
    flex: 1;

    display: -webkit-flex;
    display: flex;
    -webkit-justify-content: center;
    justify-content: center;
    -webkit-align-items: center;
    align-items: center;
    flex-wrap: wrap;
}

.c-navbar__body__left__home--back {
    width: 22px;
    height: 22px;
    box-sizing: border-box;
}

.c-navbar__body__left__home--home {
    width: 19px;
    height: 19px;
    box-sizing: border-box;
}

.c-navbar__body__left__home--division {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);

    width: 1px;
    height: 20px;
    background-color: rgba(0, 0, 0, .1);
}

.c-navbar__body--slot {
    flex: 1;
}

.c-blank-block {
    width: 100vw;
    height: calc(var(--statusBarHeight) + var(--navBarHeight));
    background-color: transparent;
}


index.json

{
    "component": true,
    "usingComponents": {}
}


属性

属性 描述 默认值

title 标题 hello world

showGoBack 显示返回按钮 false

showHome 显示返回主页按钮 false

position 是否开启绝对定位 false

bgColor 导航栏背景颜色 white

titleColor 导航栏标题颜色 #000000

showSlot 是否开启slot false

showBlankBlock 是否开启空白块占位 false


使用

index.json

{
    "usingComponents": {
        "wmp-navbar": "@chenbz/wmp-navbar"
    },
    "navigationStyle": "custom"
}

index.wxml

<view>
  <wmp-navbar title="标题"></wmp-navbar>
</view>


npm

组件已打包发布到npm,欢迎移步至@chenbz/wmp-navbar


原文链接:https://blog.csdn.net/weixin_42863549/article/details/126449900




博客评论
还没有人评论,赶紧抢个沙发~
发表评论
说明:请文明发言,共建和谐网络,您的个人信息不会被公开显示。