zoukankan      html  css  js  c++  java
  • 微信小程序自定义导航栏组件

    1.首先,要在json文件中设置为自定义的形式

    "navigationStyle": "custom"
    

    2.计算相关值

    导航栏分为状态栏和标题栏,只要能算出每台手机的导航栏高度问题就迎刃而解

    • 导航栏高度 = 胶囊按钮高度 + 状态栏到胶囊按钮间距 * 2 + 状态栏高度

      注:由于胶囊按钮是原生组件,为表现一致,其单位在各种手机中都为 px,所以我们自定义导航栏的单位都必需是 px(切记不能用 rpx),才能完美适配。

    因为在不同的手机型号头部那条栏目高度可能不一致,所以为了我们适配更多型号,我们需要计算3个值:

    如下图:

    1. 整个导航栏的高度;

    2. 胶囊按钮与顶部的距离;

    3. 胶囊按钮与右侧的距离。

    小程序可以通过 wx.getMenuButtonBoundingClientRect() 获取胶囊按钮的信息  和 wx.getSystemInfo() 获取设备信息。

    如下图:

     通过这些信息我们可以计算出上面说的3个值:

    1. 整个导航栏高度 = statausBarHeight + height + (top-statausBarHeight )*2;

    2. 胶囊按钮与顶部的距离 = top;

    3.胶囊按钮与右侧的距离 = windowWidth - right。

    现在我们明白了原理,可以利用胶囊按钮的位置信息和 statusBarHeight 高度动态计算导航栏的高度,贴一个实现此功能最重要的方法

    let systemInfo = wx.getSystemInfoSync();
    let rect = wx.getMenuButtonBoundingClientRect ? wx.getMenuButtonBoundingClientRect() : null; //胶囊按钮位置信息
        wx.getMenuButtonBoundingClientRect();
        let navBarHeight = (function() { //导航栏高度
                let gap = rect.top - systemInfo.statusBarHeight; //动态计算每台手机状态栏到胶囊按钮间距
                return 2 * gap + rect.height;
              })();
    

    gap 信息就是不同的手机其状态栏到胶囊按钮间距,具体更多代码实现和使用 demo 请移步下方代码仓库,代码中还会有输入框文字跳动解决办法,安卓手机输入框文字飞出解决办法,左侧按钮边框太粗解决办法等等

    App.js 代码如下:

    App({
      globalData: {
       
      },
      onLaunch: function () {
        let menuButtonObject = wx.getMenuButtonBoundingClientRect();
        wx.getSystemInfo({
          success: res => {
            let statusBarHeight = res.statusBarHeight,
              navTop = menuButtonObject.top,//胶囊按钮与顶部的距离
              navHeight = statusBarHeight + menuButtonObject.height + (menuButtonObject.top - statusBarHeight)*2;//导航高度
            this.globalData.navHeight = navHeight;
            this.globalData.navTop = navTop;
            this.globalData.windowHeight = res.windowHeight;
          },
          fail(err) {
            console.log(err);
          }
        })
      }
    })
    

    3.因为这个头部导航是公共的,所以我们最好把它设置成一个组件,命名为navbar

    index.wxml

    <view class="navbar custom-class" style='height:{{navHeight}}px;background-color:{{bgColor}}'>
      <view wx:if="{{showNav}}" class="navbar-action-wrap navbar-action-group row item-center" style='top:{{navTop}}px;background-color:rgba(255,255,255,.6)'>
          <ss-icon name="back" color="{{iconColor}}" size="15px" block="{{true}}" class="navbar-action_item" bind:click="_navBack"></ss-icon>
          <ss-icon name="index" color="{{iconColor}}" size="15px" block="{{true}}" class="navbar-action_item last" bind:click="_toIndex"></ss-icon>
      </view>
      <view class='navbar-title' style='top:{{navTop}}px'>
        {{pageName}}
      </view>
    </view>
    

    index.js:

    // components/navbar/index.js
    const App = getApp();
    
    Component({
      options: {
        addGlobalClass: true,
      },
      /**
       * 组件的属性列表
       */
      properties: {
        pageName:String,
        showNav:{
          type:Boolean,
          value:true
        },
        showHome: {
          type: Boolean,
          value: true
        }
      },
    
      /**
       * 组件的初始数据
       */
      data: {
       
      },
      lifetimes: {
        attached: function () {
          this.setData({
            navH: App.globalData.navHeight
          })
         }
      },
      /**
       * 组件的方法列表
       */
      methods: {
        //回退
        navBack: function () {
            wx.navigateBack({
              delta: 1
            })      
        },
        //回主页
        toIndex: function () {
          wx.navigateTo({
            url: '/pages/admin/home/index/index'
          })
        },
      }
    })
    

    index.wxss:

    /* components/navbar/index.wxss */
    
    .navbar {
       100%;
      overflow: hidden;
      position: relative;
      top: 0;
      left: 0;
      z-index: 10;
      flex-shrink: 0;
    }
    
    .navbar-title {
       100%;
      box-sizing: border-box;
      padding-left: 115px;
      padding-right: 115px;
      height: 32px;
      line-height: 32px;
      text-align: center;
      position: absolute;
      left: 0;
      z-index: 10;
      color: #333;
      font-size: 16px;
      font-weight: bold;
      text-overflow: ellipsis;
      overflow: hidden;
      white-space: nowrap;
    }
    
    .navbar-action-wrap {
      display: -webkit-flex;
      display: flex;
      -webkit-box-align: center;
      -ms-flex-align: center;
      -webkit-align-items: center;
      align-items: center;
      position: absolute;
      left: 10px;
      z-index: 11;
      line-height: 1;
      padding-top: 4px;
      padding-bottom: 4px;
    }
    
    .navbar-action-group {
      border: 1px solid #f0f0f0;
      border-radius: 20px;
      overflow: hidden;
    }
    
    .navbar-action_item {
      padding: 3px 0;
      color: #333;
    }
    
    .navbar-action-group .navbar-action_item {
      border-right: 1px solid #f0f0f0;
      padding: 3px 14px;
    }
    
    .navbar-action-group .last {
      border-right: none;
    }
    

    index.json:

    {
      "component": true,
      "usingComponents": {
        "ss-icon": "../icon/index"
      }
    }
    

    组件已创建完毕,现在说下该组件的使用方法

    假设我们需要在index.wxml中需要调用这个组件,

    1.在index.json中引用该组件:

    {
      "usingComponents": {
        "navbar": "/components/navbar/index"
      }
    }
    

    2.在index.wxml中使用该组件:

    <view class='view-page'>
      <navbar page-name="你当前页面的名字"></navbar>
      <view class='page-content'>
        <!--这里放你的内容-->
      </view>
    </view>
    

    最后的结果如下图所示:

     3.参数说明

    胶囊信息报错和获取不到

    问题就在于 getMenuButtonBoundingClientRect 这个方法,在某些机子和环境下会报错或者获取不到,对于此种情况完美可以模拟一个胶囊位置出来

    try {
      rect = Taro.getMenuButtonBoundingClientRect ? Taro.getMenuButtonBoundingClientRect() : null;
      if (rect === null) {
        throw 'getMenuButtonBoundingClientRect error';
      }
      //取值为0的情况
      if (!rect.width) {
        throw 'getMenuButtonBoundingClientRect error';
      }
      //取值为0的情况
      if (!rect.width) {
        throw 'getMenuButtonBoundingClientRect error';
      }
    } catch (error) {
      let gap = ''; //胶囊按钮上下间距 使导航内容居中
      let width = 96; //胶囊的宽度,android大部分96,ios为88
      if (systemInfo.platform === 'android') {
        gap = 8;
        width = 96;
      } else if (systemInfo.platform === 'devtools') {
        if (ios) {
          gap = 5.5; //开发工具中ios手机
        } else {
          gap = 7.5; //开发工具中android和其他手机
        }
      } else {
        gap = 4;
        width = 88;
      }
      if (!systemInfo.statusBarHeight) {
        //开启wifi的情况下修复statusBarHeight值获取不到
        systemInfo.statusBarHeight = systemInfo.screenHeight - systemInfo.windowHeight - 20;
      }
      rect = {
        //获取不到胶囊信息就自定义重置一个
        bottom: systemInfo.statusBarHeight + gap + 32,
        height: 32,
        left: systemInfo.windowWidth - width - 10,
        right: systemInfo.windowWidth - 10,
        top: systemInfo.statusBarHeight + gap,
         width
      };
      console.log('error', error);
      console.log('rect', rect);
    }
    
    以上代码主要是借鉴了拼多多的默认值写法,android 机子中 gap 值大部分为 8,ios 都为 4,开发工具中 ios 为 5.5,android 为 7.5,这样处理之后自己模拟一个胶囊按钮的位置,这样在获取不到胶囊信息的情况下,可保证绝大多数机子完美显示导航头
     还有一种写法是胶囊按钮那部分的高度设置为40,导航栏的高度用动态的头加上40

     参考1: https://www.cnblogs.com/sese/p/9761713.html

    参考2: https://juejin.im/post/6844903916963004423

  • 相关阅读:
    927小程序繁星计划峰会 · 看完这七大话题 你会更了解阿里小程序
    不吹不黑,今天我们来聊一聊 Kubernetes 落地的三种方式
    虽然他们说是水题,但我觉得思想蛮好的
    新学dfs(看懂了)
    01背包,死记硬背(我是真的蠢)
    装箱问题(太笨、还没想通)
    高精度乘法,string中的坑
    双十一用python秒杀京东好货!
    高精度减法用string 和 stack
    n阶汉诺塔 记住吧。。
  • 原文地址:https://www.cnblogs.com/ToBeBest/p/13409699.html
Copyright © 2011-2022 走看看