uniapp 自定义微信小程序 tabBar 导航栏

背景

做了一个校园招聘类小程序,使用 uniapp + vue3 + uview-plus + pinia 构建,这个小程序要实现多角色登录,根据权限动态切换 tab 栏文字、图标。

使用pages.json中配置tabBar无法根据角色动态配置 tabBar,因此自定义tabBar,根据下面的截图说明的几种自定义方案,第一种使用custom-tab-bar组件,这个只有 H5 支持,使用 view 自己绘制 tabBar 也可以,我采用微信小程序自定义tabBar 这个方式。

目标

实现一个自定义 tabBar,能够根据登录角色显示不同的导航栏

参考文档

参考 uniapp 关于 自定义 tabBar 的说明,
uniapp 自定义tabbar
以及微信小程序自定义tabbar的文档
微信小程序自定义tabbar

项目结构

项目结构

效果图

效果图2 效果图1

实现过程

  1. 添加微信小程序custom-tab-bar组件
  2. 配置pages.json
  3. 引入pinia,创建store目录
  4. 创建tabData.ts文件,放置 tabBar 数据
  5. 创建tabs目录,标签栏对应的页面
  6. 创建标签页对应的组件
  7. App.vue中初始化

添加微信小程序custom-tab-bar组件

根据文档描述需要在根目录(cli 项目在 src 目录)下创建custom-tab-bar目录,里面是小程序wxml,wxss文件,不是vue文件。

我将custom-tab-bar组件的代码放在下面了,或者可以去微信小程序文档中下载示例代码

<!-- src/custom-tab-bar/index.wxml -->
<cover-view class="tab-bar">
  <!-- <cover-view class="tab-bar-border"></cover-view> -->
  <cover-view wx:for="{{tabBar.list}}" wx:key="index" class="tab-bar-item" data-path="{{item.pagePath}}" data-index="{{index}}" bindtap="switchTab">
    <cover-image src="{{selected === index ? item.selectedIconPath : item.iconPath}}"></cover-image>
    <cover-view style="color: {{selected === index ? selectedColor : color}}">{{item.text}}</cover-view>
  </cover-view>
</cover-view>
/* src/custom-tab-bar/index.js */
Component({
  data: {
    selected: 0,
    color: '#333333',
    selectedColor: '#1874F5',
  },
  methods: {
    switchTab(e) {
      const data = e.currentTarget.dataset
      const url = '/' + data.path
      wx.switchTab({url})
      this.setData({
        selected: data.index
      })
    }
  }
})
/* src/custom-tab-bar/index.wxss */
.tab-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  padding-bottom: env(safe-area-inset-bottom);
  height: 96rpx;
  background: white;
  box-shadow: 0 -4px 16px 0 #00000014;
  z-index: 10000;
}

.tab-bar-border {
  background-color: rgba(0, 0, 0, 0.33);
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 2rpx;
  transform: scaleY(0.5);
}

.tab-bar-item {
  flex: 1;
  text-align: center;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

.tab-bar-item cover-image {
  width: 48rpx;
  height: 48rpx;
}

.tab-bar-item cover-view {
  font-size: 20rpx;
}
// src/custom-tab-bar/index.json
{
  "component": true,
  "usingComponents": {}
}

配置pages.json

pages设置中需要引入tab对应的页面,否则在小程序中会报错

tabbar设置中添加 custom: truelist列表中的配置保留,后面在页面初始化时会被自定义 tabBar 数据覆盖

{
  "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
    {
      "path": "pages/tabs/tab1",
      "style": {
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/tabs/tab2",
      "style": {
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/tabs/tab3",
      "style": {
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/tabs/tab4",
      "style": {
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/index/index",
      "style": {
        "navigationBarTitleText": "uni-app"
      }
    }
  ],
  "tabBar": {
    "custom": true,
    "color": "#5F5F5F",
    "selectedColor": "#07c160",
    "borderStyle": "black",
    "backgroundColor": "#F7F7F7",
    "list": [
      {
        "pagePath": "pages/tabs/tab1",
        "text": "按钮1",
        "iconPath": "static/icon/icon-tab1.png",
        "selectedIconPath": "static/icon/icon-tab1-active.png"
      },
      {
        "pagePath": "pages/tabs/tab2",
        "text": "按钮2",
        "iconPath": "static/icon/icon-tab2.png",
        "selectedIconPath": "static/icon/icon-tab2-active.png"
      },
      {
        "pagePath": "pages/tabs/tab3",
        "text": "按钮3",
        "iconPath": "static/icon/icon-tab3.png",
        "selectedIconPath": "static/icon/icon-tab3-active.png"
      },
      {
        "pagePath": "pages/tabs/tab4",
        "text": "按钮4",
        "iconPath": "static/icon/icon-tab4.png",
        "selectedIconPath": "static/icon/icon-tab4-active.png"
      }
    ]
  }
}

引入pinia,创建store目录

在状态库中增加 roleId 参数,根据 roleId 参数判断角色权限

// src/store/index.ts
import {defineStore} from 'pinia'

const appStore = defineStore('app', {
  state: () => {
    return {
      roleId: '',
    }
  },
  actions: {
	setRoleId(id: string) {
      this.roleId = id
    },	
  }
 })

main.ts中引入pinia

import { createSSRApp } from "vue";
import App from "./App.vue";

import uviewPlus from "uview-plus";
import * as Pinia from "pinia";

import "uno.css";

export function createApp() {
  const app = createSSRApp(App);

  app.use(Pinia.createPinia())
  app.use(uviewPlus)

  return {
    app,
    Pinia
  };
}

创建tabData.ts文件

import useAppStore from '@/store/index'

// tabBar的data
export const tabData = {
  selected: 0,
  //底部按钮高亮下标
  tabBar: {
    custom: true,
    color: '#5F5F5F',
    selectedColor: '#07c160',
    backgroundColor: '#F7F7F7',
    list: [] as any
  }
};

// roleId == '01' 显示的导航栏
const list1 = [
  {
    pagePath: 'pages/tabs/tab1',
    text: '首页',
    iconPath: '/static/icon/icon-tab1.png',
    selectedIconPath: '/static/icon/icon-tab1-active.png'
  },
  {
    pagePath: 'pages/tabs/tab2',
    text: '标签2',
    iconPath: '/static/icon/icon-tab2.png',
    selectedIconPath: '/static/icon/icon-tab2-active.png'
  },
  {
    pagePath: 'pages/tabs/tab3',
    text: '标签3',
    iconPath: '/static/icon/icon-tab3.png',
    selectedIconPath: '/static/icon/icon-tab3-active.png'
  },
  {
    pagePath: 'pages/tabs/tab4',
    text: '我的',
    iconPath: '/static/icon/icon-tab4.png',
    selectedIconPath: '/static/icon/icon-tab4-active.png'
  }
];

// roleId == '02' 显示的导航栏
const list2 = [
  {
    pagePath: 'pages/tabs/tab1',
    text: '推荐',
    iconPath: '/static/icon/icon-tab1.png',
    selectedIconPath: '/static/icon/icon-tab1-active.png'
  },
  {
    pagePath: 'pages/tabs/tab4',
    text: '我的',
    iconPath: '/static/icon/icon-tab4.png',
    selectedIconPath: '/static/icon/icon-tab4-active.png'
  }
];

// 更新菜单
export const updateRole = (that: any, type: string) => {
  //这里设置权限
  if (type === '01') {
    tabData.tabBar.list = list1;
  } else {
    tabData.tabBar.list = list2;
  }
  tabData.selected = 0;
  useAppStore().setRoleId(type)
  updateTab(that);
};

// 更新底部高亮
export const updateIndex = (that: any, index: number) => {
  tabData.selected = index;
  updateTab(that);
};

// 更新Tab状态
export const updateTab = (that: any) => {
  if ((typeof that.getTabBar === 'function') && that.getTabBar()) {
    that.getTabBar().setData(tabData);
  }
};

创建tabs目录,标签栏对应的页面

tab4为例,其他的 tab 页类似,根据roleId渲染符合条件的组件

<!-- src/pages/tabs/tab4.vue -->
<template>
  <student-tab v-if="store.roleId === '01'" />
  <teacher-tab v-if="store.roleId === '02'" />
</template>

<script lang="ts" setup>
import { onShow } from '@dcloudio/uni-app'
import appStore from '@/store/index'
import { updateIndex } from '@/utils/tabData'

import TeacherTab from '../teacher/tabView4.vue'
import StudentTab from '../student/tabView4.vue'

const store = appStore();

onShow(() => {
  // 获取页面对象
  const page = getCurrentPages()[0]

  // 更新tabBar选中状态
  updateIndex(page, store.roleId === '02' ? 1 : 3);
})
</script>

<style lang="scss" scoped></style>

创建标签页对应的组件

以下只是示例,增加了一个切换角色的按钮

<!-- src/pages/student/tabView1.vue -->
<template>
  <!-- 状态栏占位 -->
  <view class="status-bar"></view>

  <view class="m-20">tabView1</view>

  <view class="m-20">
    <up-button type="primary" text="切换角色" @click="changeRole"></up-button>
  </view>
</template>

<script lang="ts" setup>
import { updateRole } from "@/utils/tabData";

const changeRole = () => {
  const page = getCurrentPages()[0]
  updateRole(page, "02")
}
</script>

<style lang="scss" scoped></style>

App.vue中初始化

<!-- src/App.vue -->
<script lang="ts" setup>
import { updateRole } from '@/utils/tabData'
import { onLaunch } from '@dcloudio/uni-app'

onLaunch(() => {
	updateRole({}, '01')
})
</script>

总结

以上是使用微信小程序自定义 tabBar 导航栏的主要实现过程,实现并不复杂,只是之前在开发的时候花了点时间调试,容易漏掉一些配置,导致导航栏不显示或者切换没有效果和高亮的选项不正确。

有更好的实现方式,欢迎大家分享出来看看。

还有一个问题,在微信开发者工具上看,标签栏首次点击时,还是会出现标签栏图片闪烁的情况,有知道的小伙伴欢迎指点一下。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何构建你自己的实时人脸识别系统

引言 随着人工智能技术的发展&#xff0c;人脸识别已经成为日常生活中的常见技术&#xff0c;被广泛应用于安全验证、个性化服务等多个领域。本教程将指导你如何使用Python编程语言结合OpenCV和face_recognition库来构建一个基本的人脸识别系统。我们将从安装必要的库开始&…

C++ 设计模式——解释器模式

目录 C 设计模式——解释器模式1. 主要组成成分2. 逐步构建解释器模式步骤1: 定义抽象表达式步骤2: 实现终结符表达式步骤3: 实现非终结符表达式步骤4: 构建语法树步骤5: 实现内存管理步骤6: 创建上下文和客户端 3. 解释器模式 UML 图UML 图解析 4. 解释器模式的优点5. 解释器模…

生日贺卡录放音芯片,多段音频录音ic生产厂商,NVF04M-32minute

可以录音播放的生日贺卡与传统的纸质贺卡相比&#xff0c;它有着创意以及个性的特点&#xff0c;仅需少量的电子元器件&#xff0c;即可实现录音功能&#xff0c;搭配上文字&#xff0c;让声音存储在生日贺卡里&#xff0c;让贺卡也变得有温度&#xff0c;祝福我想亲口对TA说。…

fantastic-admin前端+django后端,初始化全流程记录

fantastic-admin前端是我目前看到最完善的前端框架&#xff0c;只需要简单的设置就可以快速开始项目。 但是我本人的能力有限&#xff0c;对前端知识一知半解&#xff0c;之前废了九牛二虎之力才跑通了前后端流程&#xff0c;由于新的项目需要&#xff0c;有了开发新后台的想法…

【有啥问啥】大模型应用中的哈希链推理任务

大模型应用中的哈希链推理任务 随着人工智能技术的快速发展&#xff0c;尤其是大模型&#xff08;如GPT、BERT、Vision Transformer等&#xff09;的广泛应用&#xff0c;确保数据处理和模型推理的透明性与安全性变得愈发重要。哈希链推理任务作为一种技术手段&#xff0c;能够…

学习计算机网络

a类0~127&#xff0c;b类128~191&#xff0c;c类192~223 网络地址&#xff1a;看子网掩码&#xff0c;分网络位和主机位&#xff0c;后面是主机位&#xff0c;主机位全部为0&#xff0c;网络地址。 直接广播地址&#xff1a;看子网掩码&#xff0c;分网络位和主机位&#xff…

Jenkins构建CI/CD

CI/CD 软件开发的连续方法基于自动执行脚本&#xff0c;以最大限度地减少在开发应用程序时引入错误的可能性。从新代码的开发到部署&#xff0c;它们需要较少的人为干预甚至根本不需要干预。 它涉及在每次小迭代中不断构建&#xff0c;测试和部署代码更改&#xff0c;从而减少…

vue2+ueditor集成秀米编辑器

一、百度富文本编辑器 1.首先下载 百度富文本编辑器 下载地址&#xff1a;GitHub - fex-team/ueditor: rich text 富文本编辑器 2.把下载好的文件整理好 放在图片目录下 3. 安装插件vue-ueditor-wrap npm install vue-ueditor-wrap 4.在你所需要展示的页面 引入vue-uedito…

判断给定的一个不限长的数字串大小变化趋势、经典面试题:猴子排成圈踢出求最后剩下大王编号以及Debian服务器php中安装IMAP扩展各种报错解决过程

一、判断给定的一个不限长的数字串大小变化趋势 自制了一道面试题&#xff1a;给定一个不限长的数字字符串&#xff0c;判断每一位数字的大小变化趋势是否是^或v趋势&#xff0c;如果是就返回true&#xff0c;如果不是就返回false。比如121即属于^&#xff0c;322129即属于v。这…

Verilog和Matlab实现RGB888互转YUV444

文章目录 一、色彩空间1.1 RGB色彩空间1.2 CMYK色彩空间1.3 YUV色彩空间 二、色彩空间转换公式2.1 RGB转CMYK2.2 CMYK转RGB2.3 RGB888转YUV4442.4 YUV444转RGB888 三、MATLAB实现RGB888转YUV4443.1 matlab代码3.2 matlab结果 四、Verilog实现RGB888转YUV444 一、色彩空间 色彩空…

【区块链 + 物联网】区块链边缘计算网关设备 | FISCO BCOS应用案例

目前边缘端设备主要以人工智能应用为主&#xff0c;或以数据采集网络设备为主&#xff0c;还未有区块链边缘计算网关设备&#xff0c;难以 在依托终端设备的传统行业中进行区块链 应用。本项目研制区块链边缘计算网关&#xff0c;将区块链、计算与网络集成 在一起&#xff0c;…

单片机学习笔记

一、单片机帝国的诞生与发展 1.1 单片机的基本概念 单片机是一种集成电路芯片&#xff0c;采用超大规模的集成电路把具有数据处理功能的中央处理器存储器、输入输出端口、外围电路和相关外设集成在一块硅片上构成一个小而完整的微型计算机系统。 一般而言&#xff0c;单片机也…

Java语言程序设计基础篇_编程练习题**17.21 (十六进制编辑器)

目录 题目&#xff1a;**17.21 (十六进制编辑器) 代码示例 结果展示 题目&#xff1a;**17.21 (十六进制编辑器) 编写一个 GUI 应用程序&#xff0c;让用户在文本域输入一个文件名&#xff0c;然后按回车键&#xff0c;在文本域显示它的十六进制表达形式。用户也可以修改十六…

分类预测|基于蜣螂优化极限梯度提升决策树的数据分类预测Matlab程序DBO-Xgboost 多特征输入单输出 含基础模型

分类预测|基于蜣螂优化极限梯度提升决策树的数据分类预测Matlab程序DBO-Xgboost 多特征输入单输出 含基础模型 文章目录 一、基本原理1. 数据准备2. XGBoost模型建立3. DBO优化XGBoost参数4. 模型训练5. 模型评估6. 结果分析与应用原理总结 二、实验结果三、核心代码四、代码获…

1-9 图像膨胀 opencv树莓派4B 入门系列笔记

目录 一、提前准备 二、代码详解 kernel np.ones((3, 3), np.uint8) _, binary_image cv2.threshold(image, 127, 255, cv2.THRESH_BINARY) dilated_image cv2.dilate(binary_image, kernel, iterations1) 三、运行现象 四、完整代码 五、完整工程贴出 一、提前准备 …

scrapy 爬取微博(一)【最新超详细解析】:创建微博爬取工程

本项目属于个人学习记录&#xff0c;爬取的数据会于12小时内销毁&#xff0c;且不可用于商用。 1 初始化环境 首先我们需要有python环境&#xff0c;先安装一下python&#xff0c;然后配置环境变量&#xff0c;这边给出windows的配置&#xff1a; 我这边的安装目录是D:\pyt…

PHP轻量级高性能HTTP服务框架 - webman

摘要 webman 是一款基于 workerman 开发的高性能 HTTP 服务框架。webman 用于替代传统的 php-fpm 架构&#xff0c;提供超高性能可扩展的 HTTP 服务。你可以用 webman 开发网站&#xff0c;也可以开发 HTTP 接口或者微服务。 除此之外&#xff0c;webman 还支持自定义进程&am…

Django发送邮件

【图书介绍】《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》_django 5企业级web应用开发实战(视频教学版)-CSDN博客 Django 5框架Web应用开发_夏天又到了的博客-CSDN博客 本文学习怎么使用Django发送邮件。 尽管使用Python的smtplib模块发送电子邮件…

vant 动态查询下拉菜单(可用)

动态查询item项 <van-form submit"onSubmit" ref"formRef"><Title title"企业信息" title-line title-size"19" class"ml-[18px] mb-[18px]"></Title><van-cell-group inset class"py-[18px]&quo…

【JavaSE基础】Java 基础知识

Java 转义字符 Java 常用的转义字符 在控制台&#xff0c;输入 tab 键&#xff0c;可以实现命令补全 转义字符含义作用\t制表符一个制表位&#xff0c;实现对齐的功能\n &#xff1a;换行符\n换行符一个换行符\r回车符一个回车键 System.out.println(“韩顺平教育\r 北京”);&…