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

news2024/11/16 1:26:29

背景

做了一个校园招聘类小程序,使用 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 导航栏的主要实现过程,实现并不复杂,只是之前在开发的时候花了点时间调试,容易漏掉一些配置,导致导航栏不显示或者切换没有效果和高亮的选项不正确。

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

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

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

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

相关文章

达梦数据库的系统视图v$ifun

达梦数据库的系统视图v$ifun 达梦数据库&#xff08;DM Database&#xff09;中V$IFUN 视图是用于检测函&#xff08;Function&#xff09;信息的。 在 Oracle 数据库中&#xff0c;类似的系统视图被称为动态性能视图&#xff0c;但在达梦数据库中并没有与 Oracle 一一对应的…

QT(1)-.pro 文件 转成.vcxproj 工程

1.qtcreator创建的文件转换成vs2019可以打开的。 1.QT webenginewidgets unknown modules webenginewidgets 要用 MSVC2017 &#xff0c;用minGW 32构建

使用Django身份验证系统

【图书介绍】《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》_django 5企业级web应用开发实战(视频教学版)-CSDN博客 《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》(王金柱)【摘要 书评 试读】- 京东图书 (jd.com) Django 5框…

windows中Selenium安装最新版Chrome WebDriver

windows中Selenium安装最新版Chrome WebDriver 需求&#xff1a;需要使用 selenium 对某个网页进行截图 文章目录 windows中Selenium安装最新版Chrome WebDriver一、查看Chrome版本二、找到对应的chromedriver版本三 安装3.1 确定google安装路径3.2 将下载的google driver 解压…

解决bug: RuntimeError: Address already in use,一个linux下pytorch多卡训练tcp端口占用的bug

时间&#xff1a;2024.9.3 1&#xff09;bug&#xff1a; self._store TCPStore( # type: ignore[call-arg] RuntimeError: Address already in use2&#xff09;原因分析 linux下pytorch多卡训练深度学习模型&#xff0c;训练中途暂停训练&#xff0c;但仍有进程占用某个端…

字典树Trie(专项复习)

一.P8306 【模板】字典树 题目思路:字典树的板子题,熟练写出insert函数(建树),以及query函数(查询)即可. 代码实现: #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; typedef long long ll; #define N 3000005 #define P 131 ll f1[N]; s…

华为云征文|Flexus云服务X实例安装ODBC驱动,在ODBC中建立MySQL数据库连接,通过QT连接云数据库

引出 4核12G-100G-3M规格的Flexus X实例使用测评第2弹&#xff1a;Flexus云服务X实例安装ODBC驱动&#xff0c;在ODBC中建立MySQL数据库连接&#xff0c;通过QT连接云数据库 什么是Flexus云服务器X实例 官方解释&#xff1a; Flexus云服务器X实例是新一代面向中小企业和开发…

第140天:内网安全-横向移动局域网ARP欺骗DNS劫持钓鱼中间人单双向

目录 案例一&#xff1a;局域网&工作组-ARP原理-断网限制-单向 案例二&#xff1a;局域网&工作组-ARP欺骗-劫持数据-双向 案例三&#xff1a;局域网&工作组-DNS 劫持-钓鱼渗透-双向 案例一&#xff1a;局域网&工作组-ARP原理-断网限制-单向 原理&#xff1…

pytorch利用简单CNN实现葡萄病虫害图片识别

1 前言 之前我开发了一个葡萄病虫害的可视化系统&#xff0c;最近就想给这个系统增加2个功能&#xff0c;一个是对接一个AI助手&#xff0c;可以进行葡萄病虫害的咨询&#xff0c;直接对接千问大模型&#xff0c;这个在之前的博文里已经介绍过对接方法了&#xff0c;第二个是做…

ChatGPT与R语言融合技术在生态环境数据统计分析、绘图、模型中的实践与进阶应用

自2022年GPT&#xff08;Generative Pre-trained Transformer&#xff09;大语言模型的发布以来&#xff0c;它以其卓越的自然语言处理能力和广泛的应用潜力&#xff0c;在学术界和工业界掀起了一场革命。在短短一年多的时间里&#xff0c;GPT已经在多个领域展现出其独特的价值…

【JavaWeb】JDBCDruidTomcat入门使用

本章使用技术版本&#xff1a; Tomcatv10.1.25 关于javaweb相关的其他技术&#xff0c;比如tomcat和maven&#xff0c;在我的主页记录了笔记&#xff0c;ajax我用的是本地笔记以后再考虑上传&#xff0c;前端三板斧我用的菜鸟教程文档 JDBC 初识 JDBC概念 JDBC 就是使用Jav…

MatLab基础学习01

MatLab基础学习01 1.基础入门2.MatLab的数据类型2.1数字2.2字符串2.3矩阵2.4.元胞数组2.5结构体 3.MatLab的矩阵的操作3.1矩阵定义与构造3.2矩阵的下标取值 4.MatLab的逻辑流程4. For循环结构4.2 While循环&#xff0c;当条件成立的时候进行循环4.3 IF end 1.基础入门 matlba必…

1.3 SQL注入之MYSQL系统库

一.系统库释义 提供了访问数据库元数据的方式 元数据是关于数据库的数据&#xff0c;如数据库名和表名&#xff0c;列的数据类型或访问权限。 1.information_schema 库&#xff1a;是信息数据库&#xff0c;其中保存着关于MySQL服务器所维护的所有其他数据库的信息&#xff1…

公园智能厕所引导大屏,清楚显示厕位有无人状态

在科技飞速发展的今天&#xff0c;公园的设施也在不断与时俱进。其中&#xff0c;公园智能厕所引导大屏的出现&#xff0c;为游客带来了全新的如厕体验。 走进公园的智能厕所区域&#xff0c;首先映入眼帘的便是那醒目的引导大屏。屏幕上清晰地显示着各个厕位的有无人状态&…

如何使用Cheerio与jsdom解析复杂的HTML结构进行数据提取

背景介绍 在现代网页开发中&#xff0c;HTML结构往往非常复杂&#xff0c;包含大量嵌套的标签和动态内容。这给爬虫技术带来了不小的挑战&#xff0c;尤其是在需要精确提取特定数据的场景下。传统的解析库可能无法有效处理这些复杂的结构&#xff0c;而JavaScript环境下的Chee…

机器学习(五) -- 监督学习(8) --神经网络2

机器学习系列文章目录及序言深度学习系列文章目录及序言 上篇&#xff1a;机器学习&#xff08;五&#xff09; -- 监督学习&#xff08;8&#xff09; --神经网络1 下篇&#xff1a; 前言 tips&#xff1a;标题前有“***”的内容为补充内容&#xff0c;是给好奇心重的宝宝看…

Fast Vision Transformers with HiLo Attention

总结 提出了 HiLo Attention 机制&#xff1a; 该机制将自注意力层分为两部分&#xff1a;Hi-Fi&#xff08;高频注意力&#xff09; 和 Lo-Fi&#xff08;低频注意力&#xff09;。Hi-Fi 捕捉局部细节&#xff0c;通过在局部窗口内应用自注意力&#xff0c;减少了计算复杂度…

图文解析保姆级教程:Tomcat下载、安装、卸载、启动、关闭,解决窗口闪退问题、端口号冲突问题

文章目录 1. 下载2. 安装与卸载3. 启动与关闭4. 常见问题问题1&#xff1a;Tomcat启动时&#xff0c;窗口一闪而过问题2&#xff1a;端口号冲突&#xff08;Tomcat使用的端口被占用&#xff09; 此教程摘选自我的笔记&#xff1a;黑马JavaWeb开发笔记14——Tomcat&#xff08;介…

linux进程处理

1.测试这样没意义&#xff0c;要向后加 wait等待进程结束 1. 2.测试 发送异常结束的信号&#xff0c;通过kill 二、子进程的回收 对于子进程的结束而言&#xff0c;都希望父进程能够知道并作出一定的反应&#xff0c;通过 wait、waitpid 函数可以知道子进程是如何结束的…

人工智能训练师边缘计算实训室解决方案

一、引言 随着物联网&#xff08;IoT&#xff09;、大数据、人工智能&#xff08;AI&#xff09;等技术的飞速发展&#xff0c;计算需求日益复杂和多样化。传统的云计算模式虽在一定程度上满足了这些需求&#xff0c;但在处理海量数据、保障实时性与安全性、提升计算效率等方面…