[打怪升級]小程序自定義頭部導航欄“完美”解決方案

image

爲什麼要做這個?

主要是在項目中,智酷君發現的一些問題

  • 一些頁面是通過掃碼和訂閱消息訪問後,沒有直接可以點擊去首頁的,需要添加一個home鏈接
  • 需要添加自定義搜索功能
  • 需要自定義一些功能按鈕

某些自定義頭部功能

其實,第一個問題,在最近的微信版本更新中已經優化了,通過 小程序模板消息 過來的,系統會自動加上home按鈕,但對於其他的訪問方式則沒有支持~

一個不大不小的問題:兩邊ICON不對齊問題

頭部icon對齊問題

智酷君之前嘗試了各種解決方法,發現有一個問題,就是現在手機屏幕太多種多樣,有 傳統頭部、寬/窄劉海屏、水滴屏等等,無法八門,很多解決方案都無法解決特殊頭部,系統“膠囊按鈕” 和 自定義按鈕在Android屏幕可能有 幾像素不對齊 的問題(強迫症的噩夢)。

下面分享下一個相對比較完善的解決方案:

自定義頭部導航

小程序代碼段DEMO

Link: https://developers.weixin.qq....
ID: cuUaCimT72cH

智酷君做了一個demo代碼段,方便大家直接用IDE工具查看源碼~
IDE工具打開代碼段

頁面配置

1、頁面JSON配置
{
  "usingComponents": {
    "NavComponent": "/components/nav/common"  //以插件的方式引入
  },
  "navigationStyle": "custom"  //自定義頭部需要設置
}

如果需要自定義頭部,需要設置navigationStyle爲 “custom”

2、頁面代碼
<!-- home 類型的菜單 -->
<NavComponent v-title="自定義頭部" bind:commonNavAttr="commonNavAttr"></NavComponent>
<!-- 搜索菜單 -->
<NavComponent is-search="true" bind:commonNavAttr="commonNavAttr"></NavComponent>

可以在自定義導航標籤上添加屬性配置來設置功能,具體按照實際需要來

3、目錄結構
│
├─components
│  └─nav
│          common.js
│          common.json
│          common.wxml
│          common.wxss
│
├─images
│      back.png
│      home.png
│
└─index
        index.js
        index.json
        index.wxml
        index.wxss
        search.js
        search.json
        search.wxml
        search.wxss

僅供參考

插件對應的JS部分

components/nav/common.js部分
const app = getApp();
Component({
  properties: {
    vTitle: {
      type: String,
      value: ""
    },
    isSearch:{
      type: Boolean,
      value: false
    }
  },
  data: {
    haveBack: true, // 是否有返回按鈕,true 有 false 沒有 若從分享頁進入則沒有返回按鈕
    statusBarHeight: 0, // 狀態欄高度
    navbarHeight: 0, // 頂部導航欄高度
    navbarBtn: { // 膠囊位置信息
      height: 0,
      width: 0,
      top: 0,
      bottom: 0,
      right: 0
    },
    cusnavH: 0, //title高度
  },
  // 微信7.0.0支持wx.getMenuButtonBoundingClientRect()獲得膠囊按鈕高度
  attached: function () {
    if (!app.globalData.systeminfo) {
      app.globalData.systeminfo = wx.getSystemInfoSync();
    }
    if (!app.globalData.headerBtnPosi) app.globalData.headerBtnPosi = wx.getMenuButtonBoundingClientRect();
    console.log(app.globalData)
    let statusBarHeight = app.globalData.systeminfo.statusBarHeight // 狀態欄高度
    let headerPosi = app.globalData.headerBtnPosi // 膠囊位置信息
    console.log(statusBarHeight)
    console.log(headerPosi)
    let btnPosi = { // 膠囊實際位置,座標信息不是左上角原點
      height: headerPosi.height,
      width: headerPosi.width,
      top: headerPosi.top - statusBarHeight, // 膠囊top - 狀態欄高度
      bottom: headerPosi.bottom - headerPosi.height - statusBarHeight, // 膠囊bottom - 膠囊height - 狀態欄height (膠囊實際bottom 爲距離導航欄底部的長度)
      right: app.globalData.systeminfo.windowWidth - headerPosi.right // 這裏不能獲取 屏幕寬度,PC端打開小程序會有BUG,要獲取窗口高度 - 膠囊right
    }
    let haveBack;
    if (getCurrentPages().length != 1) { // 當只有一個頁面時,並且是從分享頁進入
      haveBack = false;
    } else {
      haveBack = true;
    }
    var cusnavH = btnPosi.height + btnPosi.top + btnPosi.bottom // 導航高度
    console.log( app.globalData.systeminfo.windowWidth, headerPosi.width)
    this.setData({
      haveBack: haveBack, // 獲取是否是通過分享進入的小程序
      statusBarHeight: statusBarHeight,
      navbarHeight: headerPosi.bottom + btnPosi.bottom, // 膠囊bottom + 膠囊實際bottom
      navbarBtn: btnPosi,
      cusnavH: cusnavH
    });
    //將實際nav高度傳給父類頁面
    this.triggerEvent('commonNavAttr',{
      height: headerPosi.bottom + btnPosi.bottom
    });
  },
  methods: {
    _goBack: function () {
      wx.navigateBack({
        delta: 1
      });
    },
    bindKeyInput:function(e){
      console.log(e.detail.value);
    }
  }
})

解決不同屏幕頭部不對齊問題的終極辦法是 wx.getMenuButtonBoundingClientRect()
這個方法從微信7.0.0開始支持,通過這個方法我們可以獲取到右邊系統膠囊的top、height、right等屬性,這樣無論是水滴屏、劉海屏、異形屏,都能完美對齊右邊系統默認的膠囊bar,完美治癒強迫症~

APP.js 部分
//app.js
App({
  /**
   * 加載頁面
   * @param {*} options 
   */
  onShow: function (options) {
   
  },
  onLaunch: async function () {
    let self = this;

    //設置默認分享
    this.globalData.shareData = {
      title: "智酷方程式"
    }

    // this.getSysInfo();
  },
  globalData: {
    //默認分享文案
    shareData: {},
    qrCodeScene: false, //二維碼掃碼進入傳參
    systeminfo: false,   //系統信息
    headerBtnPosi: false,  //頭部菜單高度
  }
});

將獲取的參數存儲在一個全局變量globalData中,可以減少反覆調用的性能消耗。

插件HTML部分

<view class="custom_nav" style="height:{{navbarHeight}}px;">
    <view class="custom_nav_box" style="height:{{navbarHeight}}px;">
        <view class="custom_nav_bar" style="top:{{statusBarHeight}}px; height:{{cusnavH}}px;">
            <!-- 搜索部分-->
            <block wx:if="{{isSearch}}">
                <input class="navSearch"
                    style="height:{{navbarBtn.height-2}}px;line-height:{{navbarBtn.height-4}}px; top:{{navbarBtn.top+1}}px; left:{{navbarBtn.right}}px; border-radius:{{navbarBtn.height/2}}px;"
                    maxlength="10" bindinput="bindKeyInput" placeholder="輸入文字搜索" />
            </block>
            <!-- HOME 部分-->
            <block wx:else>
                <view class="custom_nav_icon {{!haveBack||'borderLine'}}"
                    style="height:{{navbarBtn.height}}px;line-height:{{navbarBtn.height-2}}px; top:{{navbarBtn.top}}px; left:{{navbarBtn.right}}px; border-radius:{{navbarBtn.height/2}}px;">
                    <view wx:if="{{haveBack}}" class="icon-back" bindtap='_goBack'>
                        <image src='/images/back.png' mode='aspectFill' class='back-pre'></image>
                    </view>
                    <view wx:if="{{haveBack}}" class='navbar-v-line'></view>
                    <view class="icon-home">
                        <navigator class="home_a" url="/pages/home/index" open-type="switchTab">
                            <image src='/images/home.png' mode='aspectFill' class='back-home'></image>
                        </navigator>
                    </view>
                </view>
                <view class="nav_title" style="height:{{cusnavH}}px; line-height:{{cusnavH}}px;">
                    {{vTitle}}
                </view>
            </block>
        </view>
    </view>
</view>

主要是對幾種狀態的判斷和定位的計算。

插件CSS部分

/* components/nav/test.wxss */
.custom_nav {
    width: 100%;
    background: #3a7dd7;
    position: relative;
    z-index: 99999;
}
.custom_nav_box {
    position: fixed;
    width: 100%;
    background: #3a7dd7;
    z-index: 99999;
    border-bottom: 1rpx solid rgba(255, 255, 255, 0.3);
}
.custom_nav_bar {
    position: relative;
    z-index: 9;
}
.custom_nav_box .nav_title {
    font-size: 28rpx;
    color: #fff;
    text-align: center;
    position: absolute;
    max-width: 360rpx;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin: auto;
    z-index: 1;
}
.custom_nav_box .custom_nav_icon {
    position:absolute;
    z-index: 2;
    display: inline-block;
    border-radius: 50%;
    vertical-align: top;
    font-size:0;
    box-sizing: border-box;
}
.custom_nav_box .custom_nav_icon.borderLine {
    border: 1rpx solid rgba(255, 255, 255, 0.3);
    background: rgba(0, 0, 0, 0.1);
}
.navbar-v-line {
    width: 1px;
    margin-top: 14rpx;
    height: 32rpx;
    background-color: rgba(255, 255, 255, 0.3);
    display: inline-block;
    vertical-align: top;
}
.icon-back {
    display: inline-block;
    width: 74rpx;
    padding-left: 20rpx;
    vertical-align: top;
    /* margin-top: 12rpx;
    vertical-align: top; */
    height: 100%;
}
.icon-home {
    /* margin-top: 8rpx;
    vertical-align: top; */
    display: inline-block;
    width: 80rpx;
    text-align: center;
    vertical-align: top;
    height: 100%;
}
.icon-home .home_a {
    height: 100%;
    display: inline-block;
    vertical-align: top;
    width: 35rpx;
}
.custom_nav_box .back-pre,
.custom_nav_box .back-home {
    width: 35rpx;
    height: 35rpx;
    vertical-align: middle;
}
.navSearch {
  width: 200px;
  background: #fff;
  font-size: 14px;
  position: absolute;
  padding: 0 20rpx;
  z-index: 9;
}

總結

  • 通過微信API:

getMenuButtonBoundingClientRect(),結果各類手機屏幕的適配問題

  • 將算好的參數存儲在全局變量中,一次計算全局使用,爽YY~

往期回顧:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章