小程序自定义导航自适应组件

这篇具有很好参考价值的文章主要介绍了小程序自定义导航自适应组件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 前言

小程序开发中,有时我们不需要自带的导航栏,那就需要自己写一个这样的导航栏。

2. 效果展示

小程序自定义导航自适应组件,小程序

3.文件目录结构

├── root
    │   ├── components
    │   │   └── navbar
    │   │       ├── index.js
    │   │       ├── index.wxml
    │   │       ├── index.json
    │   │       ├── index.wxss
    │   ├──pages
    │   │       ├── index.js
    │   │       ├── index.wxml
    │   │       ├── index.json
    │   │       ├── index.wxss
    └──── app.js

4.如何使用

pages/index

<navbar navbar-data="{{navbarData}}"></navbar>

Page({
  data: {
    navbarData: {
      showCapsule: 1, //是否显示头部左上角小房子 1显示 0 不显示
      showBack: 1, //是否显示返回 1显示 0不显示
      // showColor: 0, //navbar背景颜色 1展示 0不展示
      // navigationBarColor: 'yellow',
      bgTransparent: true, // 时候否透明
      iconColor: 'black',
      titleColor: 'black',
      title: '首页'
    },
  },
})

5. 实现代码

需要现在app.js启动的时候获取一些信息
app.js

// app.js
App({
  onLaunch() {
    const { statusBarHeight, titleBarHeight } = getStatusBarHeight()
    console.log(statusBarHeight, titleBarHeight)
    this.globalData.statusBarHeight = statusBarHeight;
    this.globalData.titleBarHeight = titleBarHeight;
  },
  globalData: {
    statusBarHeight: "",
    titleBarHeight: ""
  }
})
function getStatusBarHeight() {
  let res = wx.getSystemInfoSync()
  let customTitleBarHeight;
  try {
    const menuInfo = wx.getMenuButtonBoundingClientRect();
    if (equalVersion(res.version, "7.0.3")) {
      customTitleBarHeight =
        menuInfo.height + (menuInfo.top - res.statusBarHeight) * 2;
    } else {
      customTitleBarHeight = menuInfo.height + menuInfo.top * 2;
    }
  } catch (e) {
    customTitleBarHeight = 48;
  }
  if (res.model.indexOf("iPhone") !== -1) {
    customTitleBarHeight = 44;
  }
  return {
    statusBarHeight: res.statusBarHeight,
    titleBarHeight: customTitleBarHeight,
  }
};

function equalVersion(curV, reqV) {
  let arr1 = curV.split(".");
  let arr2 = reqV.split(".");

  let maxL = Math.max(arr1.length, arr2.length);
  let pos = 0;
  let diff = 0;

  while (pos < maxL) {
    diff = parseInt(arr1[pos]) - parseInt(arr2[pos]);
    console.log(diff, parseInt(arr1[pos]), parseInt(arr2[pos]));
    if (diff != 0) {
      break;
    }
    pos++;
  }
  if (diff > 0 || diff == 0) {
    //新版本、稳定版
    return 1;
  } else {
    // 旧版本
    return 0;
  }
}

下面是组件代码
component/navbar.js

/**
 * 自定义头部
 */

const app = getApp()

// 版本号比较函数
function compareVersion(v1, v2) {
    v1 = v1.split('.')
    v2 = v2.split('.')
    const len = Math.max(v1.length, v2.length)
    while (v1.length < len) {
        v1.push('0')
    }
    while (v2.length < len) {
        v2.push('0')
    }
    for (let i = 0; i < len; i++) {
        const num1 = parseInt(v1[i])
        const num2 = parseInt(v2[i])
        if (num1 > num2) {
            return 1
        } else if (num1 < num2) {
            return -1
        }
    }
    return 0
}


Component({
    properties: {
        navbarData: { //navbarData   由父页面传递的数据,变量名字自命名
            type: Object,
            value: {},
            observer: function (newVal, oldVal, changedPath) {
                if (newVal == null && typeof (oldVal) == 'object') {
                    try {
                        var _o = {};
                        var defaultData = {
                            statusBarHeight: '',
                            titleBarHeight: '',
                            navbarData: {
                                showCapsule: 1, //是否显示左上角小房子 1显示 0 不显示
                                showBack: 1, //是否显示返回 1显示 0不显示
                                showColor: 1, //navbar背景颜色 1蓝色 0白色
                                navigationBarColor: '#ffffff',
                                bgTransparent: false, // true 背景为透明 false 不透明(下面两个属性也不生效)
                                iconColor: 'black', // white 左侧icon颜色
                                titleColor: '#000000' // 可以指定title具体色值
                            }
                        }

                        _o['navibarData'] = defaultData['navbarData']
                        this.setData(_o);
                    } catch (e) {

                    }
                } else {
                    // var data = this.data;
                    var data = {};
                    var path = 'navibarData';
                    Object.keys(newVal).forEach(key => {
                        data[`${path}.${key}`] = newVal[key];
                    })
                    this.setData(data);
                }
            }
        }
    },

    data: {
        statusBarHeight: '',
        titleBarHeight: '',
        showNavbar: '',
        menuButtonInfo: {},
        navibarData: {
            showCapsule: 0, //是否显示左上角小房子
            showBack: 1, //是否显示返回
            showColor: 1, //navbar背景颜色,
            navigationBarColor: '#ffffff',
            bgTransparent: false, // true 背景为透明 false 不透明(下面两个属性也不生效)
            iconColor: 'black', // white 左侧icon颜色
            titleColor: '#000000' // 可以指定title具体色值
        }
    },
    attached: function () {
        if (wx.getSystemInfoSync().platform.toLowerCase().indexOf('devtools') != -1) {
            this.setData({
                showNavbar: true
            });
        } else {
            // 获取版本号
            const version = wx.getSystemInfoSync().version
            if (compareVersion(version, '7.0.0') >= 0) {
                // 版本号大于7.0.0时,显示自定义头部
                this.setData({
                    showNavbar: true
                })
            } else {
                //   // 版本号低于7.0.0时,隐藏自定义头部
                this.setData({
                    showNavbar: false
                })
            }
        }
        this.setData({
            statusBarHeight: app.globalData.statusBarHeight,
            titleBarHeight: app.globalData.titleBarHeight
        });
        //获取右上角胶囊的大小,为显示自定义icon做准备
        this.setData({
            menuButtonInfo: wx.getMenuButtonBoundingClientRect()
        });
    },
    ready() {
        try {
            const currentPages = getCurrentPages()
            const _o1 = {}
            //无论如何返回按钮出现的规则不变
            if (currentPages.length > 1) {
                _o1.showBack = true;
            } else {
                _o1.showBack = false;
            }
            this.setData({
                navibarData: {
                    ...this.data.navibarData,
                    ..._o1
                }
            })
        } catch (e) {

        }
    },
    methods: {
        //返回到首页
        _backhome(e) {
            wx.switchTab({
                url: '/pages/home/homepage',
            });
        },
        _backlast(e) {
            wx.navigateBack();
        },
    },
})

component/navbar.wxml

<view style="padding-top:{{navibarData.bgTransparent ? 0 : (statusBarHeight+titleBarHeight)}}px" wx:if='{{showNavbar}}'>
  <view wx:if='{{navibarData.bgTransparent}}' class="nav-wrap b-nav-wrap transparent-bg">
    <template is="titleBarContent" data="{{statusBarHeight,titleBarHeight,navibarData,menuButtonInfo}}"/>
  </view>
  <block wx:else>
    <view wx:if='{{navibarData.showColor}}' class="nav-wrap" style='background-color:{{navibarData && navibarData.navigationBarColor}};'>
      <template is="titleBarContent" data="{{statusBarHeight,titleBarHeight,navibarData,menuButtonInfo}}"/>
    </view>
    <view wx:else class="nav-wrap b-nav-wrap">
      <template is="titleBarContent" data="{{statusBarHeight,titleBarHeight,navibarData,menuButtonInfo}}"/>
    </view>  
  </block>
</view>

<template name="titleBarContent">
  <view class="status-bar" style="height:{{statusBarHeight}}px"></view>
    <view class="title-bar" style="height:{{titleBarHeight}}px">
      <view class="title-bar-group {{navibarData.showBack ^ navibarData.showCapsule ? 'only-group-icon' : navibarData.showBack && navibarData.showCapsule ? '' :'no-group-icon'}}">
        <view class="title-bar-icon" bindtap='_backlast' wx:if='{{navibarData.showBack}}'>
          <image wx:if="{{navibarData.bgTransparent&&navibarData.iconColor == 'white'}}" src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAApVBMVEUAAAD///+4/eNVAAAANnRSTlMACPH9+vbrsCsF5LwTDALcPTYhAd/Ik4J4ZFRMRkIyG9LNt6SZjGAvFg/Z1cKnoIdyaFomm2zHx4MpAAABcElEQVRYw+2YaXKCQBhEhwFRcEXBfd8xxpiYzP2PltR0pbzA+5FU8Q7w/tD012AqKir+B8F8ifp6qXM70DeJ3A8NStcZOs8J8rWa8m0HjK/Rle81YHwz63Xh2DCMQ++zMyh9O+fpQg94tZGv2WJ8WSrfMGF8x5rXRe9Qmg/OE/cYX7mVb91nfI+LfPU245tb+UbQ23ZXmmtTKM0350mhSj0X8hVnxrdM5btB5fKhNId3KM1vzmPnjK9dl+/yYHz9F/m2JeNbxPIdOtDbESnNR8NQKi5xht1y79usDMXBd31gMPa+rTqc8MidIxHk3MEUmeVOumjk3OgQrSs3i0Syd3Qav6LnMUYbIpoYQXWYBg3Zsso4ewdyZRy8VFaHHlyGoaYIwaogx5LWNTrntP/pjM/scxKz31D7xMBfedczVj9DGfMT+qWsMUvRi7m5Lfrr34zT9VNgD3swknFhMKY1/XPgWHad+zQkySIzFRUVf41vKdVQ6T8ZiacAAAAASUVORK5CYII=' mode='aspectFit' class='back-home-return'></image>
          <image wx:else src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAAkFBMVEUAAAAzMzMzMzM1NTU6Ojo/Pz8zMzMzMzNEREQzMzMzMzM0NDRnZ2czMzMzMzMzMzMzMzM0NDQ0NDQ0NDQ2NjY3Nzf///8zMzMzMzMzMzMzMzMzMzMzMzM0NDQ0NDQzMzM0NDQ1NTU9PT0zMzMzMzMzMzMzMzM0NDQzMzM3Nzc3Nzc0NDQzMzM0NDQ2NjYzMzP3PMnqAAAAL3RSTlMA+vErDwj2sATs3TYC5uHQuU09MSETAdfJvaWak4J4ZEZCC8OgjGlgVRwYh3JaJmpD+NcAAAFhSURBVFjD7ZdbjoJAFAUbfKEIylsFBRREHbX3v7sxfTtxA/Uxk1ALqB8qtw9qZGTkfzBrEtQXB1p3oK929IcJpVtXWpPC6VZ825zxTVbiO8wYX+SK76QYTqJzI6i+g/hW0Pe478S3zxifH4iv8hjfMDc65wrV3GvDMmZr3qSM712Ib3FmfI2t+ZgzvqdjdPMbVHOnDSF0Uh+25suDrbmDjsvL1vyEav6xx6WBal6Ir3gzvtTWvJ0yvnYpvn7N+Bpb80C9baHxBb6CqOW43BVFb279TGGU5lqtOeHAFSOcQ+7BFHyXe9KFSciNDiG7cLNI8EpN13h1vo8xeiGcGjOmBTlo5Mqik0veAbrx15xu3A/IKSKvPTmWZF2jc072P9145H4nMfsPVWKNZ3s7xLDGvQqcikINjlkhXtKNpxvb+BR7D+352XmUMT+KsVUYN3N+EsWRfBovFYnX+mpkZOSv8Qvxhkf6bCYPxwAAAABJRU5ErkJggg==' mode='aspectFit' class='back-home-return'></image>
        </view>
        <view class="line" wx:if='{{navibarData.showBack && navibarData.showCapsule}}'></view>
        <view class="title-bar-icon" bindtap='_backhome' wx:if='{{navibarData.showCapsule}}'>
          <image wx:if="{{navibarData.bgTransparent&&navibarData.iconColor == 'white'}}" src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAAXVBMVEUAAAD///9RKvvlAAAAHnRSTlMA9kNVhvo95i4VAuzgsHxjWhwH0Me9uaugcE82JiScUXyNAAABNElEQVRYw+3Wx3KEMBBF0YYZRYY4Oen/P9MuyviBEVNluhcOuuuno21T6tfW3e+dIOfOKgR1dlJeXoS+IhfysvBRlst6EPkeRFkPIt+DKOtB5HsQZT2IfA8i1+OL8PgiPDkRHl+EJyfC44vw5ER4fBGenAiPL8KTE+HxRXhyIjy+CE9OhMcX4cmJ8PgiPElRw1sr6rHnTWBnPKE2CNQS8ju+t/M0yh6Ki67WWpW+FAdLszZrwU3/PIEJ/O+gKrfvlUoKNJb6rBECm2HQCIFuGDghEIsEJvDvgAYL8z0wj89PWJzii5zitfF5jUW9eNXEO0Zvlg6DLnoDHWmpZzZfK02jtJovsictVqvZ+kaTbrM/VU0vsvvpunzQlx7ldLG39DKvr9uhqnEUyTXV5+SqPaVSP683QHRHUsVUZh0AAAAASUVORK5CYII=' mode='aspectFit' class='back-home'></image>
          <image wx:else src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAAXVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC5BxTwAAAAHnRSTlMA9kNVhvo95i4VAuzgsHxjWhwH0Me9uaugcE82JiScUXyNAAABNElEQVRYw+3Wx3KEMBBF0YYZRYY4Oen/P9MuyviBEVNluhcOuuuno21T6tfW3e+dIOfOKgR1dlJeXoS+IhfysvBRlst6EPkeRFkPIt+DKOtB5HsQZT2IfA8i1+OL8PgiPDkRHl+EJyfC44vw5ER4fBGenAiPL8KTE+HxRXhyIjy+CE9OhMcX4cmJ8PgiPElRw1sr6rHnTWBnPKE2CNQS8ju+t/M0yh6Ki67WWpW+FAdLszZrwU3/PIEJ/O+gKrfvlUoKNJb6rBECm2HQCIFuGDghEIsEJvDvgAYL8z0wj89PWJzii5zitfF5jUW9eNXEO0Zvlg6DLnoDHWmpZzZfK02jtJovsictVqvZ+kaTbrM/VU0vsvvpunzQlx7ldLG39DKvr9uhqnEUyTXV5+SqPaVSP683QHRHUsVUZh0AAAAASUVORK5CYII=' mode='aspectFit' class='back-home'></image>
        </view>
      </view>
      <view style="flex-grow:1;height:100%;background-color: transparent; display: flex; justify-content:{{navibarData.iconData.align?(navibarData.iconData.align==='right'?'flex-end':'flex-start'):'flex-start'}};">
      <view style="display: flex;align-items: center;height: 100%;">
      </view>
      </view>
      <view style="width:{{menuButtonInfo.width}}px;height:100%;background-color: transparent;"></view> 
      <view class='nav-titleContainer'>
        <view wx:if="{{navibarData.bgTransparent}}" class="nav-title" style="color:{{navibarData.titleColor}}">{{navibarData.title}}</view>
        <view wx:else class="nav-title">{{navibarData.title}}</view>
      </view>
    </view>
</template>

component/navbar.wxss

/* 顶部要固定定位 */
.nav-wrap {
  position: fixed;
  width: 100%;
  top: 0;
  z-index: 99;
  background: #ffffff;
}
/* 标题要居中 */
.nav-titleContainer {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  position: absolute;
  top:0;
  left:0;
  height: 100%;
  width: 100%;
  pointer-events: none;
}
.nav-title {
  margin: 0 180rpx;
  text-align: center;
  /* width: 50%; */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 36rpx;
  color: #000000;
  font-weight: 600;
  z-index: -1;
}

.back-home {
  width: 40rpx;
  height: 40rpx;
  cursor: pointer;
}
.back-home-return {
  width: 40rpx;
  height: 40rpx;
  cursor: pointer;
}

.title-bar-group {
  border: 1rpx solid rgba(255,255,255,0.25);
  background: rgba(0,0,0,0.12);
  border-radius: 32rpx;
  display: flex;
  height: 64rpx;
  width: 174rpx;
  box-sizing: border-box;
  align-items:center;
  overflow: hidden;
}

.title-bar-group.only-group-icon {
  border: none;
  background: transparent;
  width: 87rpx;
}

.title-bar-group.no-group-icon {
  border: none;
  background: transparent;
  width: 0rpx;
}

.title-bar-group.no-group-icon + .nav-titleContainer {
  justify-content:flex-start;
}

.title-bar-group.no-group-icon + .nav-titleContainer .nav-title {
  margin: 0 180rpx 0 12rpx;
  text-align:left;
}

.title-bar-icon {
  flex: auto;
  display:flex;
  align-items:center;
  justify-content:center;
  height:100%;
}

.line{
  height: 38rpx;
  border-left: 1px solid rgba(255,255,255,0.12);
}

.title-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 0 20rpx;
  position: relative;
}

.b-nav-wrap.nav-wrap {
  background: #fff;
}
.b-nav-wrap .nav-title {
  color: #111;
}
.b-nav-wrap .title-bar-group {
  border: 1rpx solid rgba(0,0,0,0.12);
  background: #ffffff;
}
.b-nav-wrap .line{
  border-left: 1px solid rgba(0,0,0,0.12);
}

.b-nav-wrap .title-bar-group.only-group-icon {
  border: none;
  background: transparent;
  width: 87rpx;
}

.b-nav-wrap .title-bar-group.no-group-icon {
  border: none;
  background: transparent;
  width: 0rpx;
}

.b-nav-wrap.nav-wrap.transparent-bg,
.b-nav-wrap.nav-wrap.transparent-bg .title-bar-group {
  background: transparent;
}

6. 原理分析

小程序自定义导航自适应组件,小程序

wx.getSystemInfoSync(); // 获取到状态栏的信息
wx.getMenuButtonBoundingClientRect(); // 获取胶囊的信息文章来源地址https://www.toymoban.com/news/detail-802426.html

function getStatusBarHeight() {
  let res = wx.getSystemInfoSync()
  let customTitleBarHeight;
  try {
    const menuInfo = wx.getMenuButtonBoundingClientRect(); // 获取胶囊的信息
    if (equalVersion(res.version, "7.0.3")) {
      customTitleBarHeight =
        menuInfo.height + (menuInfo.top - res.statusBarHeight) * 2;
    } else {
      customTitleBarHeight = menuInfo.height + menuInfo.top * 2;
    }
  } catch (e) {
    customTitleBarHeight = 48;
  }
  if (res.model.indexOf("iPhone") !== -1) {
    customTitleBarHeight = 44;
  }
  return {
    statusBarHeight: res.statusBarHeight, // 状态栏的高度
    titleBarHeight: customTitleBarHeight, // title的高度
  }
};

到了这里,关于小程序自定义导航自适应组件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 记录一下小程序自定义导航栏消息未读已读小红点,以及分组件的消息数量数据实时读取

    本案例,Message 身为组件,使用不了任何钩子来重新获取 this.getMessageList() 消息列表 使用 props 父子传参,因为 Message 组件使用不了页面生命周期从而无法拿到传递过来的数据 使用 watch 监听不到 props 更不建议使用本地存储,那样和 props 结果差不多 案例中采用的是发送全局事

    2024年04月10日
    浏览(43)
  • 简洁简约个人导航页引导源码PC手机自适应模板自定义背景以及音乐带后台包学会搜索引擎可收录

    简洁简约个人导航页引导源码PC手机自适应模板自定义背景以及音乐带后台包学会 搜索引擎可收录       获取源码:https://pan.baidu.com/s/1gbnBmL35RhzGuZ5P0Mk7tA?pwd=h06o 提取码:h06o  

    2024年02月07日
    浏览(108)
  • [自定义 Vue 组件] 小尾巴顶部导航栏(2.0) TailTopNav

    文章归档:https://www.yuque.com/u27599042/coding_star/oglrqteg8fzvvzn0 [自定义 Vue 组件] 响应式顶部导航栏(1.0) TopNav:https://www.yuque.com/u27599042/coding_star/hzltsltxgavwx8u2 [自定义 Vue 组件] 小尾巴 Logo 组件(2.0) TailLogo:https://www.yuque.com/u27599042/coding_star/mluie83zdzaf40sy [自定义 Vue 组件] 小尾巴下拉菜

    2024年02月05日
    浏览(38)
  • 小程序导航穿透且自定义导航栏

    需求 实现小程序隐藏头部导航栏,且导航栏穿透无高度,并且要定义返回事件 在 app.json 里面把 “navigationStyle” 设置为 “custom” 这样子之后页面就只会保留右上角胶囊按钮。

    2024年02月16日
    浏览(37)
  • 小程序自定义导航栏

    app.json文件下 app.js文件 组件文件components文件夹下新增navBar文件 index.js index.wxss index.wxml 使用 js

    2024年02月16日
    浏览(42)
  • 微信小程序自定义顶部导航,滚动页面顶部导航颜色渐变

    微信小程序自定义顶部导航栏,使背景图置顶;当向上滚动页面时,实现顶部导航颜色渐变 实现方法 代码如下(示例): 提示:由于不同的手机机型顶部导航高度不一样,所有要获取手机的信息 总共三步: 1、初始化获取顶部导航信息 2、顶部导航文字上方通过view占位,同

    2024年02月11日
    浏览(55)
  • Uniapp-小程序自定义导航栏

    制作小程序页面时候发现原生导航栏有一定的高度是没有背景渲染的会出现这种情况 但是我们需要的是 小程序的原生导航栏存在。一般可以使用 纯色填充顶部栏 可以直接使用navigationBarBackgroundColor完成 在style中添加 \\\"navigationBarBackgroundColor\\\": \\\"#FED000\\\" 但是业务需求需要添加自

    2024年02月05日
    浏览(34)
  • uniapp小程序自定义头部导航

    我们在开发小程序时,自带的头部导航样式往往不能满足需求,故只能自定义导航,接下来简要介绍下如何实现: 1. 去除自带的头部导航 要想自定义头部导航,首先要到pages.json文件夹中,找到对应页面,然后在style中写上代码: 2.封装自定义的头部导航 一个小程序,可能会

    2024年02月11日
    浏览(56)
  • 微信原生小程序自定义顶部导航

    都2023了,自定义顶部导航应该不是什么新鲜事了,这里只是简单记录下 微信自己也提供了自定义顶部导航 navigation-bar ,大概看了下,可配置的也不少,所以看需求了,如果简单可以采用微信提供的,老规矩,先看效果 状态栏高度(getSystemInfoSync),就是手机顶部网络那块的

    2024年02月15日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包