Uniapp 自定义 Tabbar 实现教程

news2025/7/14 13:08:48

Uniapp 自定义 Tabbar 实现教程

    • 1. 简介
    • 2. 实现步骤
      • 2.1 创建自定义 Tabbar 组件
      • 2.2 配置 pages.json
      • 2.3 在 App.vue 中引入组件
    • 3. 实现过程中的关键点
      • 3.1 路由映射
      • 3.2 样式设计
      • 3.3 图标处理
    • 4. 常见问题及解决方案
      • 4.1 页面跳转问题
      • 4.2 样式适配问题
      • 4.3 性能优化
    • 5. 扩展功能
      • 5.1 添加徽标
      • 5.2 添加动画效果
    • 6. 总结

1. 简介

在 Uniapp 开发中,自定义 Tabbar 是一个常见的需求。本教程将详细介绍如何实现一个美观且功能完整的自定义 Tabbar,并分享在实现过程中可能遇到的问题和解决方案。

自定义图示

2. 实现步骤

2.1 创建自定义 Tabbar 组件

首先,我们需要创建一个自定义的 Tabbar 组件。以下是完整的实现代码:

<template>
    <!-- 自定义 Tabbar 容器 -->
    <view class="custom-tabbar">
        <!-- 遍历 tabList 生成 Tabbar 项 -->
        <view 
            v-for="(item, index) in tabList" 
            :key="index" 
            class="tabbar-item" 
            :class="{'tabbar-item-active': current === index}" 
            @click="switchTab(item.pagePath)"
        >
            <!-- 使用 Vant UI 的图标组件 -->
            <van-icon 
                :name="current === index ? item.selectedIcon : item.icon" 
                class="tabbar-icon" 
                :class="{'tabbar-icon-active': current === index}" 
            />
            <text>{{ item.text }}</text>
        </view>
    </view>
</template>

<script>
// 定义路由映射关系,用于快速查找当前页面对应的索引
const TAB_ROUTES = {
    '/pages/index/index': 0,
    '/pages/detail/detail': 1,
    '/pages/course/course': 2,  
    '/pages/profile/profile': 3
};

export default {
    data() {
        return {
            current: 0,  // 当前选中的 tab 索引
            tabList: [
                {
                    pagePath: '/pages/index/index',
                    text: '首页',
                    icon: 'home-o',
                    selectedIcon: 'home-o'
                },
                {
                    pagePath: '/pages/detail/detail',
                    text: '详情',
                    icon: 'records',
                    selectedIcon: 'records'
                },
                {
                    pagePath: '/pages/course/course',  
                    text: '课程',
                    icon: 'clock-o',
                    selectedIcon: 'clock-o'
                },
                {
                    pagePath: '/pages/profile/profile',
                    text: '我的',
                    icon: 'contact',
                    selectedIcon: 'contact'
                }
            ]
        }
    },
    methods: {
        // 切换 tab 的方法
        switchTab(url) {
            uni.switchTab({ url });
        }
    },
    watch: {
        // 监听路由变化,更新当前选中的 tab
        '$route.path': {
            immediate: true,
            handler(path) {
                this.current = TAB_ROUTES[path] || 0;
            }
        }
    }
}
</script>

<style>
/* Tabbar 容器样式 */
.custom-tabbar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    height: 110rpx;
    display: flex;
    justify-content: space-around;
    align-items: center;
    background-color: #fff;
    border-top: 1rpx solid #e2e8f0;
    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
    z-index: 9999;
    padding-bottom: env(safe-area-inset-bottom);  /* 适配全面屏 */
}

/* Tabbar 项基础样式 */
.tabbar-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    font-size: 24rpx;
    color: #64748b;
    padding: 10rpx 0;
    transition: all 0.2s ease;
    position: relative;
}

/* 激活状态样式 */
.tabbar-item-active {
    color: #3b82f6;
    font-weight: 600;
}

/* 点击效果 */
.tabbar-item:active {
    transform: scale(0.95);
}

/* 图标样式 */
:deep(.tabbar-icon) {
    font-size: 48rpx !important;
    margin-bottom: 4rpx;
}

/* 激活状态图标样式 */
:deep(.tabbar-icon-active) {
    color: #3b82f6 !important;
}

/* 文字样式 */
.tabbar-item text {
    margin-top: 6rpx;
    font-weight: 500;
}

/* 底部指示条 */
.tabbar-item-active:before {
    content: '';
    position: absolute;
    bottom: -10rpx;
    left: 50%;
    transform: translateX(-50%);
    width: 16rpx;
    height: 3px;
    background: #3b82f6;
    border-radius: 3px;
}
</style>

2.2 配置 pages.json

pages.json 中需要禁用原生 Tabbar,并配置页面路由:

{
    "tabBar": {
        "custom": true,  // 启用自定义 Tabbar
        "list": [
            {
                "pagePath": "pages/index/index",
                "text": "首页"
            },
            {
                "pagePath": "pages/detail/detail",
                "text": "详情"
            },
            {
                "pagePath": "pages/course/course",  
                "text": "课程"
            },
            {
                "pagePath": "pages/profile/profile",
                "text": "我的"
            }
        ]
    }
}

2.3 在 App.vue 中引入组件

App.vue 中引入并注册自定义 Tabbar 组件:

<template>
    <view>
        <custom-tabbar />
    </view>
</template>

<script>
import CustomTabbar from '@/components/CustomTabbar.vue'

export default {
    components: {
        CustomTabbar
    }
}
</script>

3. 实现过程中的关键点

3.1 路由映射

使用 TAB_ROUTES 对象来映射路由路径和对应的索引值,这样可以方便地管理当前选中的 tab:

const TAB_ROUTES = {
    '/pages/index/index': 0,
    '/pages/detail/detail': 1,
    '/pages/course/course': 2,  
    '/pages/profile/profile': 3
};

3.2 样式设计

  • 使用 position: fixed 确保 Tabbar 固定在底部
  • 添加 env(safe-area-inset-bottom) 适配全面屏手机
  • 使用 box-shadow 添加阴影效果
  • 实现点击缩放动画效果
  • 添加底部指示条

3.3 图标处理

使用 van-icon 组件(来自 Vant UI)来显示图标,通过 :class 动态切换选中状态。

4. 常见问题及解决方案

4.1 页面跳转问题

问题:使用 uni.switchTab 跳转时可能出现页面不更新的情况。

解决方案

  • 确保在 pages.json 中正确配置了 tabBar
  • 使用 uni.switchTab 而不是 uni.navigateTo
  • watch 中监听路由变化,及时更新选中状态

4.2 样式适配问题

问题:在不同机型上可能出现底部遮挡或样式错乱。

解决方案

  • 使用 env(safe-area-inset-bottom) 适配全面屏
  • 设置合适的 z-index 确保层级正确
  • 使用 rpx 单位确保在不同设备上显示一致

4.3 性能优化

问题:频繁切换可能导致性能问题。

解决方案

  • 使用 v-for 时添加 :key
  • 合理使用 watch 监听路由变化
  • 避免在 Tabbar 中加载过多资源

5. 扩展功能

5.1 添加徽标

可以在 Tabbar 项上添加徽标,显示未读消息数量等:

<view class="tabbar-item">
    <van-icon :name="icon" />
    <text>{{ text }}</text>
    <view v-if="badge" class="badge">{{ badge }}</view>
</view>

5.2 添加动画效果

可以添加更丰富的动画效果,如:

.tabbar-item {
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.tabbar-item:hover {
    transform: translateY(-5rpx);
}

6. 总结

通过以上步骤,我们实现了一个功能完整、样式美观的自定义 Tabbar。这个实现方案具有以下特点:

  1. 支持路由跳转
  2. 适配不同机型
  3. 提供良好的视觉反馈
  4. 性能优化
  5. 易于扩展

作者:xuan
个人博客:https://blog.ybyq.wang
欢迎访问我的博客,获取更多技术文章和教程。

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

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

相关文章

记录一次使用面向对象的C语言封装步进电机驱动

简介 (2025/4/21) 本库对目前仅针对TB6600驱动下的42步进电机的基础功能进行了一定的封装, 也是我初次尝试以面向对象的思想去编写嵌入式代码, 和直流电机的驱动步骤相似在调用stepmotor_attach()函数和stepmotor_init()函数之后仅通过结构体数组stepm然后指定枚举变量中的id即…

Spark-streaming核心编程

1.导入依赖‌&#xff1a; <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-streaming-kafka-0-10_2.12</artifactId> <version>3.0.0</version> </dependency> 2.编写代码‌&#xff1a; 创建Sp…

vue3+TS+echarts 折线图

需要实现的效果如下 <script setup lang"ts" name"RepsSingleLineChart">import * as echarts from echartsimport { getInitecharts } from /utils/echartimport type { EChartsOption } from echarts// 定义 props 类型interface Props {id: strin…

小火电视桌面TV版下载-小火桌面纯净版下载-官方历史版本安装包

别再费心地寻找小火桌面的官方历史版本安装包啦&#xff0c;试试乐看家桌面吧&#xff0c;它作为纯净版本的第三方桌面&#xff0c;具有诸多优点。 界面简洁纯净&#xff1a;乐看家桌面设计简洁流畅&#xff0c;页面简洁、纯净无广告&#xff0c;为用户打造了一个干净的电视操…

androidstudio安装配置

B站配置视频AndroidStudio安装配置教程&#xff08;最新版本教程&#xff09;3分钟搞定 快速安装使用_哔哩哔哩_bilibili 1、环境变量 D:\AndroidSdk ANDROID_HOME ANDROID_SDK_HOME 2、新建 3、配置 distributionUrlhttps://mirrors.cloud.tencent.com/gradle/gradle-8.11.1-…

《AI大模型趣味实战》基于RAG向量数据库的知识库AI问答助手设计与实现

基于RAG向量数据库的知识库AI问答助手设计与实现 引言 随着大语言模型&#xff08;LLM&#xff09;技术的快速发展&#xff0c;构建本地知识库AI问答助手已成为许多企业级应用的需求。本研究报告将详细介绍如何基于FLASK开发一个使用本地OLLAMA大模型底座的知识库AI问答助手&…

BeeWorks Meet:私有化部署视频会议的高效选择

在数字化时代&#xff0c;视频会议已成为企业沟通协作的重要工具。然而&#xff0c;对于金融、政务、医疗等对数据安全和隐私保护要求极高的行业来说&#xff0c;传统的公有云视频会议解决方案往往难以满足其严格的安全标准。此时&#xff0c;BeeWorks Meet 私有化部署视频会议…

IPv6 技术细节 | 源 IP 地址选择 / Anycast / 地址自动配置 / 地址聚类分配

注&#xff1a;本文为 “IPv6 技术细节” 相关文章合集。 部分文章中提到的其他文章&#xff0c;一并引入。 略作重排&#xff0c;未整理去重。 如有内容异常&#xff0c;请看原文。 闲谈 IPv6 - 典型特征的一些技术细节 iteye_21199 于 2012-11-10 20:54:00 发布 0. 巨大的…

【工具】使用 MCP Inspector 调试服务的完全指南

Model Context Protocol (MCP) Inspector 是一个交互式开发工具&#xff0c;专为测试和调试 MCP 服务器而设计。本文将详细介绍如何使用 Inspector 工具有效地调试和测试 MCP 服务。 1. MCP Inspector 简介 MCP Inspector 提供了直观的界面&#xff0c;让开发者能够&#xff…

【音视频】AVIO输入模式

内存IO模式 AVIOContext *avio_alloc_context( unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t (*seek)(…

Uniapp:scroll-view(区域滑动视图)

目录 一、基本概述二、属性说明三、基本使用3.1 纵向滚动3.2 横向滚动一、基本概述 scroll-view,可滚动视图区域。用于区域滚动。 二、属性说明 属性名类型默认值说明平台差异说明scroll-xBooleanfalse允许横向滚动scroll-yBooleanfalse允许纵向滚动三、基本使用 3.1 纵向滚…

单精度浮点运算/定点运算下 MATLAB (VS) VIVADO

VIVADO中单精度浮点数IP核计算结果与MATLAB单精度浮点数计算结果的对比 MATLAB定点运算仿真&#xff0c;对比VIVADO计算的结果 目录 前言 一、VIVADO与MATLAB单精度浮点数运算结果对比 二、MATLAB定点运算仿真 总结 前言 本文介绍了怎么在MATLAB中使用单精度浮点数进行运算…

【AI插件开发】Notepad++ AI插件开发1.0发布和使用说明

一、产品简介 AiCoder是一款为Notepad设计的轻量级AI辅助插件&#xff0c;提供以下核心功能&#xff1a; 嵌入式提问&#xff1a;对选中的文本内容进行AI分析&#xff0c;通过侧边栏聊天界面与AI交互&#xff0c;实现多轮对话、问题解答或代码生成。对话式提问&#xff1a;独…

【MySQL数据库入门到精通-07 函数-字符串函数、数值函数、日期函数和流程函数】

文章目录 一、字符串函数1. MySQL中的函数主要分为以下四类&#xff1a; 字符串函数、数值函数、日期函数、流程函数。下面是字符串函数常见的函数&#xff0c;见下表。2.具体代码实现3.结果 二、数值函数1.知识点2.具体代码实现3.结果 三、日期函数1.知识点2.具体代码实现3.结…

Python图像处理——基于Retinex算法的低光照图像增强系统

1.项目内容 &#xff08;1&#xff09;算法介绍 ①MSRCR (Multi-Scale Retinex with Color Restoration) MSRCR 是多尺度 Retinex 算法&#xff08;MSR&#xff09;的扩展版&#xff0c;引入了色彩恢复机制以进一步提升图像增强质量。MSR 能有效地压缩图像动态范围&#xff…

如何在JDK17项目中改成1.8

1.调整 Spring Boot 版本 由于 Spring Boot 3.x 最低要求 JDK 17&#xff0c;所以如果要使用 JDK 8&#xff0c;需要把 spring-boot-starter-parent 的版本降低到 2.7.x 系列&#xff0c;这个系列是支持 JDK 8 的。示例如下&#xff1a; <parent><groupId>org.sp…

【不同名字的yolo的yaml文件名是什么意思】

以下是这些 YOLO 系列配置文件的详细解析&#xff0c;按版本和功能分类说明&#xff1a; 一、YOLOv3 系列 文件名核心特性适用场景yolov3.yaml原始 YOLOv3 结构&#xff0c;3 尺度预测&#xff08;13x13,26x26,52x52&#xff09;通用目标检测yolov3-spp.yaml增加 SPP&#xff…

Zephyr kernel Build System (CMake)介绍

目录 概述 1. 结构介绍 2 构建和配置阶段 2.1 配置阶段 2.2 Cmake编译 3 Zephy项目目录结构 3.1 文件架构 3.2 文件content 概述 本文主要介绍Zephyr kernel Build System CMake的功能&#xff0c;以及使用该工具构建项目&#xff0c;并详细介绍了每个目录以及目录下文…

相对论大师-记录型正负性质BFS/图论-链表/数据结构

看到这一题我的第一个思路就是双向bfs 起点是a&#xff0c;终点还是a&#xff0c;但是flag是相反的&#xff08;“越”的方向&#xff09; tip1.可以用字典vis来存储flag 刚开始初始化时vissta,visend一个对应0、1 要求两个队列相…

Jenkins流水线管理工具

文章目录 前言&#xff1a; DevOps时代的自动化核心 —Jenkins一、Jenkins是什么&#xff1f;二、Linux安装Jenkinswar包方式安装依赖环境下载 Jenkins WAR 包启动 Jenkins 服务启动日志验证配置插件镜像源 docker镜像方式安装依赖环境拉取 Jenkins 镜像运行 Jenkins 容器获取初…