微信小程序 - 自定义底部菜单栏

news2024/11/14 11:51:47

        微信小程序底部菜单栏是可以通过自定义来实现的。主要涉及:新建组件、编写组件代码、设置样式、配置导航栏、在页面中引用。自定义底部导航栏可以创建出符合项目设计需求效果,实现个性化的页面切换功能。

        如下图效果,为比较常见的中间突出半圆效果的扫码或拍照的功能键,这个是可以通过CSS进行绘制出来的。此篇,将通过案例讲解这个导航栏如何实现。

        此案例中实现功能,与之前一篇实现顶部导航栏的方式雷同,有兴趣朋友可以去了解下,地址:微信小程序 - 自定义头部导航栏开发-CSDN博客

一、配置导航栏

        在app.json文件中配置navigationStyle为custom,代码如下:

{
  "pages": [
    "pages/index/index",
    "pages/logs/logs",
    "pages/mine/index"
  ],
  "window": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "Weixin",
    "navigationBarBackgroundColor": "#ffffff",
    "navigationStyle": "custom"
  },
  "style": "v2"
}

二、新建组件

        在项目components目录中,创建Navigation底部导航栏组件,如下图:

        然后在app.json中,将其配置为全局组件,代码如下:

{
  "pages": [
    "pages/index/index",
    "pages/logs/logs",
    "pages/mine/index"
  ],
  "window": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "Weixin",
    "navigationBarBackgroundColor": "#ffffff",
    "navigationStyle": "custom"
  },
  "usingComponents": {
    "custom-header": "./components/Header/index",
    "custom-navigation": "./components/Navigation/index"
  },
  "style": "v2"
}

        然后页面中就可以直接使用custom-navigation引用了,代码如下:

<custom-navigation></custom-navigation>

三、绘制背景效果

        在页面中引入后,则可以进行编写菜单栏组件代码了,首先绘制出背景框。

index.wxml代码如下:

<!--components/Navigation/index.wxml-->
<view class="navigation-wrap">
  <view class="navigation-empty-wrap">
    <view class="empty-box"></view>
    <view class="bottom-safet-area" style="height: {{emptyHeight}}rpx;"></view>
  </view>
  <view class="fixed-nav-wrap">
    <view class="shadow-box">
      <view class="middle-circle"></view>
    </view>
    <view class="bottom-safet-area" style="height: {{emptyHeight}}rpx;"></view>
  </view>
</view>

index.wxss代码如下:

/* components/Navigation/index.wxss */
.navigation-wrap{ width: 100%; }

.fixed-nav-wrap{ width: 100%; position: fixed; left: 0; bottom: 0; z-index: 100; }
.fixed-nav-wrap .shadow-box{ 
  width: 100%; 
  min-height: 100rpx; 
  background-color: #ffffff;
  box-shadow: 0 0 10rpx rgba(0, 0, 0, .2); 
  position: relative; 
  z-index: 1; 
}
.fixed-nav-wrap .shadow-box .middle-circle{ 
  width: 150rpx; 
  height: 150rpx; 
  margin-left: -75rpx;
  border-radius: 100rpx; 
  box-shadow: 0 0 10rpx rgba(0, 0, 0, .2); 
  background-color: #ffffff;
  position: absolute; 
  left: 50%; 
  top: -45rpx; 
  z-index: 1; 
}

.navigation-empty-wrap{ width: 100%; }
.navigation-empty-wrap .empty-box{ width: 100%; height: 100rpx; }
.bottom-safet-area{ background-color: #FFF; }

        此时页面效果背景轮廓就出来了,虽然现在还不太美观,后期还需再度修饰一下。如下图:

        这里注意的几个容器:

  • navigation-empty-wrap类选择器空容器,为了解决悬浮导航不遮挡超出屏幕的内容,将页面中内容撑到底部菜单栏上面;
  • fixed-nav-wrap类选择器为悬浮的菜单栏的最外层容器;
  • shadow-box类选择器为底部轮廓样式(包含中间半圆样式);
  • bottom-safet-area类选择器,为解决部分机型底部存在突出部分,如下图:

四、完成轮廓绘制

        如上图可见,中间圆环,以及当底部有突出部分时出现的阴影,可以使用菜单容器进行覆盖,叠加在上层即可。

        首先index.wxml中增加fixed-nav-content类容器,用于渲染菜单栏内容的容器,代码如下:

<!--components/Navigation/index.wxml-->
<view class="navigation-wrap">
  <view class="navigation-empty-wrap">
    <view class="empty-box"></view>
    <view class="bottom-safet-area" style="height: {{emptyHeight}}rpx;"></view>
  </view>
  <view class="fixed-nav-wrap">
    <view class="shadow-box">
      <view class="middle-circle"></view>
    </view>
   
    <view class="fixed-nav-content">

    </view>
    <view class="bottom-safet-area" style="height: {{emptyHeight}}rpx;"></view>
  </view>
</view>

        然后index.wxss中添加fixed-nav-content类选择器样式,代码如下:

/* components/Navigation/index.wxss */
.navigation-wrap{ width: 100%; }

.fixed-nav-wrap{ width: 100%; position: fixed; left: 0; bottom: 0; z-index: 100; }
.fixed-nav-wrap .shadow-box{ 
  width: 100%; 
  min-height: 100rpx; 
  background-color: #ffffff;
  box-shadow: 0 0 10rpx rgba(0, 0, 0, .2); 
  position: relative; 
  z-index: 1; 
}
.fixed-nav-wrap .shadow-box .middle-circle{ 
  width: 150rpx; 
  height: 150rpx; 
  margin-left: -75rpx;
  border-radius: 100rpx; 
  box-shadow: 0 0 10rpx rgba(0, 0, 0, .2); 
  background-color: #ffffff;
  position: absolute; 
  left: 50%; 
  top: -45rpx; 
  z-index: 1; 
}
.navigation-empty-wrap{ width: 100%; }
.navigation-empty-wrap .empty-box{ width: 100%; height: 100rpx; }
.bottom-safet-area{ background-color: #FFF; }

.fixed-nav-content{ 
    background-color: #ffffff; 
    width: 100%; 
    height: 120rpx; 
    position: absolute; 
    left: 0; 
    top: 0; 
    z-index: 5; 
}

        最后页面中则呈现出一个完美的底部菜单栏轮廓了,如下图:

五、菜单内容渲染        

        可以在index.js增加菜单数据,在容器中渲染菜单列表数据。在类容器fixed-nav-content中,创建模拟table类容器用于渲染菜单内容。

        对于菜单列表需要对每项进行平分宽度,可以使用flex布局,也可以使用table + table-cell模拟表格属性实现。这里使用后者,table中的cell设置width:1%时,所有列会平分是因为会默认添加一个隐匿的table布局,其布局方式为table-layout: auto,且每个单元格有自己的最小宽度。

index.wxml代码如下:

<!--components/Navigation/index.wxml-->
<view class="navigation-wrap">
  <view class="navigation-empty-wrap">
    <view class="empty-box"></view>
    <view class="bottom-safet-area" style="height: {{emptyHeight}}rpx;"></view>
  </view>
  <view class="fixed-nav-wrap">
    <view class="shadow-box">
      <view class="middle-circle"></view>
    </view>
    <view class="fixed-nav-content">
      <view class="table">
        <view class="cell {{item.id===navId?'active':''}}" wx:for="{{navList}}" wx:key="index" data-id="{{item.id}}" bind:tap="jump2Event">
          <block wx:if="{{item.id==-1}}">
            <image src="../../images/scan.png" mode="aspectFill" class="scan" />
          </block>
          <block wx:else>{{item.name}}</block>
        </view>
      </view>
    </view>
    <view class="bottom-safet-area" style="height: {{emptyHeight}}rpx;"></view>
  </view>
</view>

index.wxss代码如下:

/* components/Navigation/index.wxss */
.navigation-wrap{ width: 100%; }

.fixed-nav-wrap{ width: 100%; position: fixed; left: 0; bottom: 0; z-index: 100; }
.fixed-nav-wrap .shadow-box{ 
  width: 100%; 
  min-height: 100rpx; 
  background-color: #ffffff;
  box-shadow: 0 0 10rpx rgba(0, 0, 0, .2); 
  position: relative; 
  z-index: 1; 
}
.fixed-nav-wrap .shadow-box .middle-circle{ 
  width: 150rpx; 
  height: 150rpx; 
  margin-left: -75rpx;
  border-radius: 100rpx; 
  box-shadow: 0 0 10rpx rgba(0, 0, 0, .2); 
  background-color: #ffffff;
  position: absolute; 
  left: 50%; 
  top: -45rpx; 
  z-index: 1; 
}
.navigation-empty-wrap{ width: 100%; }
.navigation-empty-wrap .empty-box{ width: 100%; height: 100rpx; }
.bottom-safet-area{ background-color: #FFF; }

.fixed-nav-content{ 
  background-color: #ffffff; 
  width: 100%; 
  height: 120rpx; 
  position: absolute; 
  left: 0; 
  top: 0; 
  z-index: 5; 
}
.fixed-nav-content .table{ display: table; width: 100%; height: 100rpx; font-size: 26rpx; }
.fixed-nav-content .table .cell{ display: table-cell; vertical-align: middle; width: 1%; text-align: center;}
.fixed-nav-content .table .cell.active{ color: #FF872E; }
.fixed-nav-content .scan{ width: 60rpx; height: 60rpx; position: relative; top: -20rpx; }

index.js代码如下:

// components/Navigation/index.js
Component({
  /**
   * 组件的初始数据
   */
  data: {
    navList: [
      {id: 1, name: "首页", path: "/pages/index/index"},
      {id: 2, name: "列表", path: ""},
      {id: -1, name: "扫码", path: ""},
      {id: 3, name: "订单", path: ""},
      {id: 4, name: "我的", path: "/pages/mine/index"}
    ],
    emptyHeight: 0
  },
  ready(){
    this.initialHeight();
  },
  /**
   * 组件的方法列表
   */
  methods: {
    // 获取底部安全距离
    initialHeight(){
      const sysInfo = wx.getSystemInfoSync();
      this.setData({
        emptyHeight: sysInfo.windowHeight - sysInfo.safeArea.bottom
      })
    }
  }
})

        注意:index.js中initialHeight()函数,则是用来初始化部分机型底部突出区域高度计算的。

        此时页面菜单栏效果如下图:

六、实现跳转

         此案例中,创建了首页和我的 两个页面,分别在里面引入custom-navigation组件。

        在custom-navigation组件index.js中添加跳转事件,代码如下:

// components/Navigation/index.js
Component({
  /**
   * 组件的初始数据
   */
  data: {
    navList: [
      {id: 1, name: "首页", path: "/pages/index/index"},
      {id: 2, name: "列表", path: ""},
      {id: -1, name: "扫码", path: ""},
      {id: 3, name: "订单", path: ""},
      {id: 4, name: "我的", path: "/pages/mine/index"}
    ],
    emptyHeight: 0
  },
  ready(){
    this.initialHeight();
  },
  /**
   * 组件的方法列表
   */
  methods: {
    // 获取底部安全距离
    initialHeight(){
      const sysInfo = wx.getSystemInfoSync();
      this.setData({
        emptyHeight: sysInfo.windowHeight - sysInfo.safeArea.bottom
      })
    },
    // 跳转
    jump2Event(e){
      const data = e.currentTarget.dataset,
            currentNav = this.data.navList.filter(item => item.id == data.id)[0];
      if(currentNav['path']) {
        wx.reLaunch({
          url: currentNav['path'],
        })
      } else if(data.id == -1){
        // 扫码
        wx.scanCode({
          success: res => {
            console.log('success', res);
          },
          fail: msg => {
            console.error(msg);
          }
        });
      }
      // if end
    }
  }
})

        当点击为中间扫码/拍照时,其data.id为-1,则启用摄像头;当点击其他菜单项时,如path链接存在,则实现跳转动作。

七、设置高亮

        为实现进入某个页面,菜单栏上显示对应栏目的高亮效果,这则需要在每个引入页面定义菜单栏时,添加相应属性告诉组件需要将哪个菜单项添加高亮。

        在组件中定义对外属性,navId为navList中每项对应的id值。代码如下:

// components/Navigation/index.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    navId: {
      type: Number,
      value: 1
    }
  },
  // 略...
})

首页代码如下:

<custom-navigation navId="1"></custom-navigation>

我的页面代码如下:

<custom-navigation navId="4"></custom-navigation>

最后在custom-navigation组件的index.wxml中,通过id判断哪个为高亮部分。代码如下:

<view class="table">
	<view class="cell {{item.id===navId?'active':''}}" 
          wx:for="{{navList}}" 
          wx:key="index" 
          data-id="{{item.id}}" 
          bind:tap="jump2Event">
	  <block wx:if="{{item.id==-1}}">
		<image src="../../images/scan.png" mode="aspectFill" class="scan" />
	  </block>
	  <block wx:else>{{item.name}}</block>
	</view>
</view>

        当navId与item.id相等时,追加active类选择器,实现高亮效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1989640.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2-58 基于matlab的图像处理 GUI 程序

基于matlab的图像处理 GUI 程序&#xff0c;功能包括裁剪、 旋转和翻转图像。 更改曝光、 对比度和饱和度&#xff0c; 黑白、 灰度等常见处理效果。程序已调通&#xff0c;可直接运行。 2-58 图像处理 GUI 程序 - 小红书 (xiaohongshu.com)

同享人力资源管理系统-TXEHR V15 hdlUploadFile.ashx 文件上传致RCE漏洞复现

0x01 产品简介 同享人力资源管理系统(TXEHR V15)是一款专为现代企业设计的人力资源管理软件解决方案,旨在通过先进的信息化手段提升企业人力资源管理的效率与水平。该系统集成了组织人事、考勤管理、薪资核算、招聘配置、培训发展、绩效管理等核心模块,并提供了灵活的配置…

大数据-41 Redis 类型集合(2) bitmap位操作 geohash空间计算 stream持久化消息队列 Z阶曲线 Base32编码

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; HadoopHDFSMapReduceHiveFlumeSqoopZookeeperHBaseRedis &#xff08;正在更新&#xff09; 章节内容 上一…

高校实验室预约系统的设计与实现-计算机毕业设计源码58031

摘要 随着信息技术的不断发展&#xff0c;高校实验室资源的管理和利用愈发重要。为了提高实验室资源的利用率和管理效率&#xff0c;我们设计并实现了一款基于Spring Boot框架的高校实验室预约系统。 本系统旨在为学生提供一个便捷、高效的途径来预约实验室资源&#xff0c;并为…

html+css+js网页设计星巴克作业2个页面(带js)

htmlcssjs网页设计 星巴克作业2个页面&#xff08;带js&#xff09; 网页作品代码简单&#xff0c;可使用任意HTML编辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#…

Linux系统驱动(九)IO模型---异步通知IO模型

文章目录 一、概念二、异步通知IO模型驱动实现&#xff08;一&#xff09;异步通知IO模型实现1. fcntl(fd,F_GETFL)调用流程2. fcntl(fd,F_SETFL,flags|FASYNC)3. fcntl(fd,F_SETOWN,getpid()) &#xff08;二&#xff09;驱动层提供异步通知模型1. 驱动层中实现异步通知IO模型…

基于QT实现的简易WPS(已开源)

一、开发工具及开源地址&#xff1a; 开发工具&#xff1a;QTCreator &#xff0c;QT 5 开源地址&#xff1a; GitHub - Whale-xh/WPS_official: Simple WPS based on QTSimple WPS based on QT. Contribute to Whale-xh/WPS_official development by creating an acc…

【JavaEE初阶】定时器

&#x1f4d5; 引言 定时器是什么&#xff1f; 定时器也是软件开发中的一个重要组件. 类似于一个 “闹钟”. 达到一个设定的时间之后, 就执行某个指定好的代码 定时器是一种实际开发中非常常用的组件.比如网络通信中, 如果对方 500ms 内没有返回数据, 则断开连接尝试重连.比如…

CTFHUB-web-RCE-过滤目录分隔符

开启题目 从源码发现管道符被过滤&#xff0c;使用分号 &#xff1b;分隔符&#xff0c;拼接执行注入&#xff0c;发现了 flag 的可疑文件 127.0.0.1;ls 查看 flag_is_here&#xff0c;发现有一个flag_12069946857.php 127.0.0.1;ls flag_is_here 查看flag_12069946857.php&a…

react项目中使用redux和reduxjs/toolkit案例

1、安装依赖 npm i react-redux reduxjs/toolkit2、在store/modules文件夹中新建todo.js &#xff08;billSlice.js&#xff09; // 账单列表 import { createSlice } from reduxjs/toolkit import axios from axiosconst billStore createSlice({name: billStore,// 数据状态…

零基础学习Python(五)

1. 数据描述符与非数据描述符 首先&#xff0c;描述符只能作用于类属性&#xff0c;如果将描述符作用于对象属性&#xff0c;则不会生效。 class D:def __get__(self, instance, owner):print("~get")class C:def __init__(self):self.x D() 应该将D对象赋值给类C…

72.树形列表绑定对应的右键菜单

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;易道云信息技术研究院 上一个内容&#xff1a;71.对象数据存储设计 以 71.对象数据存储设计 它的代码为基础进行修改 效果图&#xf…

后端常见问题及深度解决方案

&#x1f41f;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢编程&#x1fab4; &#x1f421;&#x1f419;个人主页&#x1f947;&#xff1a;Aic山鱼 &#x1f420;WeChat&#xff1a;z7010cyy &#x1f988;系列专栏&#xff1a;&#x1f3de;️ 前端-JS基础专栏✨前…

linux脚本: 检测多个服务端口是否处于侦听状态或监听状态

目录 一、背景 1、系统监控和健康检查 2、安全性评估 3、故障排查 4、合规性检查 5、资源管理 6、服务依赖性检查 二、需求和分析 1、需求 2、分析 三、脚本文件 1. 创建脚本文件 2. 编写脚本代码 3、代码解释 &#xff08;1&#xff09;定义要检查的端口列表 …

视觉全能!自回归要反超扩散?Lumina-mGPT:任意分辨率丝滑逼真图像生成(上海AI Lab)

文章链接&#xff1a;https://arxiv.org/pdf/2408.02657 git链接&#xff1a;https://github.com/Alpha-VLLM/Lumina-mGPT 亮点直击 通过多模态生成预训练的自回归Transformer&#xff0c;而不是从头训练&#xff0c;可以作为逼真的文本到图像生成和视觉与语言任务统一的有效初…

Linux shell编程:监控进程CPU使用率并使用 perf 抓取高CPU进程信息

0. 概要 本文将介绍一个用于监控一组进程CPU使用率的Shell脚本&#xff0c;&#xff0c;当检测到某进程的CPU使用率超出阈值时&#xff0c;使用 perf 工具抓取该进程的详细信息。 本shell脚本为了能在普通嵌入式系统上运行做了妥协和优化。 1. shell脚本流程的简要图示&#…

Spring 中请求作用域的数据存储在 ThreadLocal 中还是 Spring 容器中?

微信中阅读,欢迎👏👏👏关注公众号:CodeFit 。 创作不易,如果你觉得这篇文章对您有帮助,请不要忘了 点赞、分享 和 关注,为我的 持续创作 提供 动力! 最近看到一个有趣的问题,Request Scope(请求作用域) 的数据是存储在 ThreadLocal 中,还是 Spring 容器中? 事…

前端(六):Vue组件库Element

一、引入 Element&#xff1a;是饿了吗团队研发&#xff0c;一套为开发者、设计师和产品经理准备的基于vue2.0的桌面端组件库。组件&#xff1a;组成网页的部件&#xff0c;例如超链接、按钮、图片、表格、表单、分页条等。官网&#xff1a;https://element.eleme.cn/#/zh-CN …

景芯SoC DDR子系统

Memory子系统主要由DDR Controller和DDR_PHY(含DDR_IO)两个部分组成。DDR Controller主要承担其它子系统&#xff08;如CPU&#xff09;与Memory子系统进行数据交互时的传输效率及调度&#xff0c;DDR_PHY主要负责数据交互过程中的传输速度。 DDR内存接口IP解决方案包括DDR控制…

Revit二次开发选择过滤器,SelectionFilter

过滤器分为选择过滤器与规则过滤器 规则过滤器可以看我之前写的这一篇文章: Revit二次开发在项目中给链接模型附加过滤器 选择过滤器顾名思义就是可以将选择的构件ID集合传入并加入到视图过滤器中,有一些场景需要对某些构件进行过滤选择,但是没有共同的逻辑规则进行筛选的情况…