更新记录
1.2.5(2026-08-03)
更新文档
1.2.4(2026-07-29)
优化ios端底部tabbar图标展示
1.2.3(2026-07-23)
更新md文档h5端体验地址
查看更多平台兼容性
uni-app x(4.75)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| √ | √ | √ | √ | √ | √ |
其他
| 多语言 | 暗黑模式 | 宽屏模式 |
|---|---|---|
| √ | × | √ |
sunrains-tabbar-pro 插件使用指南
体验h5端
点击查看安卓端录屏效果v1.0.8
点击查看H5、IOS、鸿蒙、微信小程序端录屏效果v1.1
需要服务端(Java)源码 进群交流
服务端示例支持 1:网络请求解解密,验签,返回结果加密;2:身份证ocr识别 3:人脸注册,识别,人证比对 4:活体检测
目录
- [1.功能列表及各平台兼容汇总]
- [2. 基础配置]
- [3. 动态配置 TabBar]
- [4. 数字角标功能]
- [5. 主题配置]
- [6. page页跳转自定义tab页]
- [7. 拓展底部tabbar类型,(切换、弹出、进入)页面]
- [8. 多层级tabbar,可返回上一层,返回首层]
- [9. tabbar与tab页之前事件驱动]
- [10. mine.uvue示例代码 ]
-
[11. 同层级tab页跳转tab页]
1.功能列表及各平台兼容汇总
| 功能\平台 | Android | iOS | HarmonyOS | 微信小程序 | H5 |
|---|---|---|---|---|---|
| 动态tabbar | ✔ | ✔ | ✔ | ✔ | ✔ |
| 数字角标 | ✔ | ✔ | ✔ | ✔ | ✔ |
| 主题切换 | ✔ | ✔ | ✔ | ✔ | ✔ |
| page页跳转tab页 | ✔ | ✔ | ✔ | ✔ | ✔ |
| tabbar类型,(切换、弹出、进入)页面 | ✔ | ✔ | ✔ | ✔ | ✔ |
| 多层级tabbar | ✔ | ✔ | ✔ | ✔ | ✔ |
| tabbar与tab页之间事件驱动 | ✔ | ✔ | ✔ | ✔ | ✔ |
| 多层级tabbar虚拟按键返回 | ✔ | ✘ | ✔ | ✘ | ✘ |
| 同层级所有tab页不切换层级时只加载一次 | ✔ | ✔ | ✔ | ✘ | ✔ |
| 同层级tab页跳转tab页(类型都是tabPage) | ✔ | ✔ | ✔ | ✔ | ✔ |
注: 同层级所有tab页不切换层级时只加载一次(tab页remount为false时),指定的tab页 remount 为true时同层tabbar每次切换到该tab页都重新挂载页面(其他为false的可以不在重新挂载、卸载),切换到其它tab页时卸载,只对tabType为tabPage有效
2. 基础配置
2.1 配置 tabbar-config.uts(可以是任何名称,配置在自己项目中,用于 App.uvue 初始化操作,或相关逻辑直接写在 App.uvue里) 文件
在项目中新建 tabbar-config.uts 初始化文件,配置注册全局tab组件和导航栏设置。
完整示例:
import {
setNavbarConfig, setComponentRegistry, setDefaultTabItems, RefreshTabbarType, CustomThemeType, TabbarIconType, TabbarStyleType, refreshTabbar,
TabItemType, getStoreLoginItems, NavBarConfigType, clearStorage, getBaseTabItemsIndexKey,setDefTheme,setTabPageTheme
} from '@/uni_modules/sunrains-tabbar-pro/utssdk/outtypes'
//导入所有自定义tab页
import Recommend from '@/pages/home/recommend.uvue'
import Order from '@/pages/order/order.uvue'
import Mine from '@/pages/mine/mine.uvue'
import Detail from '@/pages/detail/detail.uvue'
import A from '@/pages/dj/a.uvue'
import B from '@/pages/dj/b.uvue'
import C from '@/pages/dj/c.uvue'
import D from '@/pages/dj/d.uvue'
import E from '@/pages/dj/e.uvue'
import F from '@/pages/dj/f.uvue'
import G from '@/pages/dj/g.uvue'
import H from '@/pages/dj/h.uvue'
import XLSX from '@/pages/dj/xlsx.uvue'
console.log("=================加载tabbar-config===========================")
//注册所有需要切换的tab页或需要弹出的页面 即类型为 tabPage:tab页面 tabPop:弹窗组件
setComponentRegistry('home', Recommend);
setComponentRegistry('order', Order);
setComponentRegistry('mine', Mine);
setComponentRegistry('detail', Detail);
setComponentRegistry('A', A);
setComponentRegistry('B', B);
setComponentRegistry('C', C);
setComponentRegistry('D', D);
setComponentRegistry('E', E);
setComponentRegistry('F', F);
setComponentRegistry('G', G);
setComponentRegistry('H', H);
setComponentRegistry('XLSX', XLSX);
// 2. 配置导航栏(不设置会使用默认配置且默认配置显示导航栏)
let setNavbarConf : NavBarConfigType = {
showTitle: false,//是否显示tab页 导航栏
titleFontSize: 34,
titleFontWeight: 'bold',
titleColor: '#333333',
navBarBackgroundColor: '#ffffff',
navBarBackgroundImage: "",
navBarHeight: 88
}
setNavbarConfig(setNavbarConf)
/**
* 默认主题
* openApp 是否是启动APP
*/
function defTheme(openApp:boolean) {
//主题背景类型 IMG COLOR
let bgType = "COLOR"
//背景 如果是图片传图片路径 颜色则传 具体颜色
let bg : string = "green"
let navBarConfig : NavBarConfigType = {
showTitle: false,//是否显示tab页 导航栏
titleFontSize: 34,
titleFontWeight: 'bold',
titleColor: '#333333',
navBarBackgroundColor: '#ffffff',
navBarBackgroundImage: "",
navBarHeight: 88
}
let tabbarIcon : TabbarIconType = {
key: "mine",
icon: '/static/tab/main3.png',
activeIcon: '/static/tab/main3_active.png',
eventIcon: "",
iconW: 48, iconH: 48,
fontSize: 24,
fontColor: "black",
activeFontColor: "white",
fontWeight: "bold"
}
let tabbarIcon1 : TabbarIconType = {
key: "home",
icon: '/static/tab/main1.png',
activeIcon: '/static/tab/main1_active.png',
eventIcon: "",
iconW: 48, iconH: 48,
fontSize: 24,
fontColor: "black",
activeFontColor: "white",
fontWeight: "bold"
}
let tabbarIcons : Map<string, TabbarIconType> = new Map();
tabbarIcons.set("mine", tabbarIcon)
tabbarIcons.set("home", tabbarIcon1)
let tabbarStyle : TabbarStyleType = {
tabbarHeight: 120,
bgColor: "grey",
tabbarIcons: tabbarIcons
}
let theme : CustomThemeType = {
bgType: bgType,
bg: bg,
navBarConfig: navBarConfig,
tabbarStyle: tabbarStyle
}
if(openApp){
setDefTheme(theme)
}else{
setTabPageTheme(theme)
}
}
/**
* 初始化tabbar区域按钮
*
* 3. 设置默认 Tabbar 列表(至少设置一个固定的,也可以全部设置,其它可通过请求服务端接口动态配置),
* 或通过网络请求初始化 游客 显示哪些 有 角色的 按角色 初始化
* tabType 值为 page时 path 必传页面路径(例如 /pages/detail/detail ) ,当为其他值时 传空字符串即可
* App.uvue onLaunch 初始化
* import {initDefaultTabItems} from '@/uni_modules/sunrains-tabbar-pro'
* onLaunch(() => {
* console.log('App Launch')
* initDefaultTabItems()
* }
*/
export function initDefaultTabItems() {
let home : TabItemType = {
key: 'home',
path: "",
fontSize: 24,
fontColor: "black",
activeFontColor: "white",
fontWeight: "bold",
name: '首页',
icon: '/static/tab/main1.png',
activeIcon: '/static/tab/main1_active.png',
eventIcon: '',
iconW: 48,
iconH: 48,
tabType: "tabPage",
remount:false,
enableEvent: false
}
let mine : TabItemType =
{
key: 'mine',
path: "",
fontSize: 24,
fontColor: "black",
activeFontColor: "white",
fontWeight: "bold",
name: '我的',
icon: '/static/tab/main3.png',
activeIcon: '/static/tab/main3_active.png',
eventIcon: '',
iconW: 48,
iconH: 48,
tabType: "tabPage",
remount:true,
enableEvent: false
}
let items : null | Array<TabItemType> = null
try {
items = getStoreLoginItems();
} catch (err) {
console.log(1111)
clearStorage("all")
}
let isLogin = true
//判断是否登录
if (isLogin) {
if (items == null) {
setDefaultTabItems([
home, mine
],
"home" //设置首页
)
defTheme(true)
} else {
let key : string | null = getBaseTabItemsIndexKey()
setDefaultTabItems(items, key ?? items[0].key)
}
} else {
setDefaultTabItems([
home, mine
],
"mine" //设置首页
)
defTheme(true)
}
}
/**
* 退出登录
*/
export function loginOut() {
clearStorage("all")
let home : TabItemType = {
key: 'home',
path: "",
fontSize: 24,
fontColor: "black",
activeFontColor: "white",
fontWeight: "bold",
name: '首页',
icon: '/static/tab/main1.png',
activeIcon: '/static/tab/main1_active.png',
eventIcon: '',
iconW: 48,
iconH: 48,
tabType: "tabPage",
remount:false,
enableEvent: false
}
let mine : TabItemType =
{
key: 'mine',
path: "",
fontSize: 24,
fontColor: "black",
activeFontColor: "white",
fontWeight: "bold",
name: '我的',
icon: '/static/tab/main3.png',
activeIcon: '/static/tab/main3_active.png',
eventIcon: '',
iconW: 48,
iconH: 48,
tabType: "tabPage",
remount:true,
enableEvent: false
}
const res : RefreshTabbarType = {
indexKey: "mine",
tabItems: [home, mine],
type: "refreshBase"
}
//重置tabbar
refreshTabbar(res);
//设置默认主题,非必须
defTheme(false);
}
在APP.uvue中导入配置
import {initDefaultTabItems} from './tabbar-config.uts'
onLaunch(() => {
initDefaultTabItems()
}
关键步骤说明:
- 导入组件:将所有需要作为 Tab 的页面组件导入
- 注册组件:使用
setComponentRegistry注册每个组件(第一个参数为唯一标识,即 TabItemType 的 key) - 配置导航栏:可选配置,根据项目需求调整
- 设置默认 Tab:至少配置一个固定 Tab,其余可动态添加
2.2 必需配置
必须在 pages.json 中配置自定义 TabBar 入口页面(必须放在第一个位置),tab页无需在pages.json中配置:
{
"pages": [{
"path": "uni_modules/sunrains-tabbar-pro/utssdk/custompage",
"style": {
"navigationStyle": "custom"
}
}
]
}
2.2 完整示例
{
"pages": [{
"path": "uni_modules/sunrains-tabbar-pro/utssdk/custompage",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/detail/detail",
"style": {
"navigationBarTitleText": "详情"
}
},
{
"path": "pages/dj/i",
"style": {
"navigationBarTitleText": "页面i"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app x",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {}
}
注意事项:
- 自定义 TabBar 入口页面必须配置在
pages数组的第一位 - 所有 Tab 页面不需要在
pages中声明 navigationStyle设置为"custom"以隐藏原生导航栏
2.3 微信小程序端配置
4.1 配置 mp-tab-renderer.uvue
注意: 仅在需要支持微信小程序时需要配置,App 端可忽略此步骤。
在 uni_modules/sunrains-tabbar-pro/utssdk/mp-tab-renderer.uvue 中配置:
//导入所有需要在tabbar区域的页面
<template>
<view style="width: 100%; height: 100%;">
<Recommend v-if="currentTab === 'home'" style="width: 100%; height: 100%;" />
<Order v-if="currentTab === 'order'" style="width: 100%; height: 100%;" />
<Mine v-if="currentTab === 'mine'" style="width: 100%; height: 100%;" />
<Detail v-if="currentTab === 'detail'" style="width: 100%; height: 100%;" />
</view>
</template>
<script setup lang="uts">
//导入所有需要在tabbar区域的页面
import Recommend from '@/pages/home/recommend.uvue'
import Order from '@/pages/order/order.uvue'
import Mine from '@/pages/mine/mine.uvue'
import Detail from '@/pages/detail/detail.uvue'
interface Props {
currentTab : string
}
defineProps({
currentTab: {
type: String
}
})
</script>
配置说明:
- 条件编译:使用
#ifndef MP-WEIXIN和#ifdef MP-WEIXIN区分平台 - App 端:使用
<component :is="...">动态渲染组件 - 小程序端:必须静态导入并声明所有可能的 Tab 组件
- 导入位置:在
#ifdef MP-WEIXIN块内导入组件
3. 动态配置 TabBar
3.1 使用场景
当需要根据用户权限、服务端配置等动态调整 TabBar 时,可以在任意页面触发刷新。
3.2 实现示例
以下面文档 mine.uvue 页面为例:
关键点:
- 使用 refreshTabbar方法触发 TabBar 刷新
- 确保所有动态 Tab 对应的组件已在
tabbar-config.uts中注册
4. 数字角标功能
4.1 功能说明
支持为任意 Tabbar 设置数字角标,用于显示未读消息数、待处理事项等。
特性:
- ✔ 动态设置/更新角标
- ✔ 超过 99 自动显示 "99+"
- ✔ 角标为 0 或 null 时不显示
- ✔ 响应式更新,立即生效
4.2 使用方法
方法一:通过调用方法设置(推荐)
在任意页面通过 调用 setTabBadge 方法:
import { setTabBadge} from '@/uni_modules/sunrains-tabbar-pro/utssdk/outtypes'
// 设置算法 tab 的角标为 5
setTabBadge("order",5)
// 清除角标(设置为 0)
setTabBadge("order",0)
// 设置超过 99 显示 99+
setTabBadge("order",150)
方法二:初始化时设置
在创建 TabItemType 时传入 badge 参数:
import { TabItemType } from '@/uni_modules/sunrains-tabbar-pro/utssdk/outtypes'
// 带角标的 tab
let mine:TabItemType =
{
key: 'home',
path: "",
fontSize: 12,
fontColor: "red",
activeFontColor: "black",
fontWeight: "bold",
name: '首页',
icon: '/static/tab/main1.png',
activeIcon: '/static/tab/main1_active.png',
eventIcon:'',
iconW: 24,
iconH: 24,
tabType: "tabPage",
enableEvent:false,
badge: 20 //不写则不带角标
}
4.3 完整示例
以 文档后面 mine.uvue 页面为例,实现动态设置角标功能:
4.4 实际应用场景
场景 1:算法未读数
// 从服务端获取未读算法数
async function loadUnreadOrderCount() {
const res = await getOrderCount()
setTabBadge("order",res.data.count)
}
// 页面加载时调用
onShow(() => {
loadUnreadOrderCount()
})
场景 2:消息通知
// WebSocket 收到新消息
websocket.onMessage((msg) => {
if (msg.type === 'new_message') {
const currentBadge = getCurrentBadge('message')
setTabBadge("newMessage",currentBadge + 1)
}
})
场景 3:购物车数量
// 添加商品到购物车后更新角标
function addToCart(product: Product) {
cartItems.push(product)
setTabBadge("cart",cartItems.length)
}
5. 主题切换
5.1 主题功能说明
插件支持自定义 TabBar 的主题样式,支持网络背景图、本地图片背景图、纯颜色背景(支持rgba透明)、导航栏、tabbar区域背景、图标大小、图标(支持网络图标)、文字颜色、文字大小、等属性 满足不同项目的视觉需求。
主题特性:
- ✔ 支持全局主题配置
- ✔ 支持动态切换主题
- ✔ 支持自定义主题参数
5.2 初始化时配置主题
可在 tabbar-config.uts 文件中配置主题
5.3 动态切换主题
在任意页面通过调用 setTabPageTheme 方法动态切换主题:
import {CustomThemeType} from '@/uni_modules/sunrains-tabbar-pro/utssdk/outtypes'
// 动态修改背景色和选中颜色
let theme : CustomThemeType = {
bgType: bgType,
bg: bg,
navBarConfig: navBarConfig,
tabbarStyle: tabbarStyle
}
setTabPageTheme(theme)
5.4 在页面中动态切换主题
以下面mine.uvue为例,实现主题切换功能
5.5 主题配置注意事项
- 颜色格式:颜色值必须为有效的 CSS 颜色格式(如
#ffffff、rgb(255,255,255)等) - tabbar区域高度单位:高度值为数字类型,单位为 rpx
- 动态修改:通过
setTabPageTheme(theme)动态修改的主题会立即生效
6 page页跳转自定义tab页
使用 pageToTab 方法 跳转到tab页
以 detail.uvue 页面为例,实现主题切换功能:
<template>
<view class="detail-root">
<view class="detail-content">
<view class="con">
<view class="com">
<text>网络通信</text>
</view>
<view class="com1">
<view>
<text style="margin-left: 10px;">服务端(java)源码</text>
</view>
<view>
<uni-link style="margin-right: 10px;font-size: 20px;color: red;" blankFallback="copy-link-modal"
href="https://gitee.com/sunyinhuia/sunrains-java" target="_blank">
点击查看
</uni-link>
</view>
</view>
<view>
<button class="btn" type="primary" @click="req">不签名、不加密访问</button>
<button class="btn" type="primary" @click="reqSm2">签名访问</button>
<button class="btn" type="primary" @click="reqSm4">加密访问</button>
<button class="btn" type="primary" @click="reqSm2Sm4">签名、加密访问</button>
</view>
</view>
<view class="con">
<view class="com">
<text>跳转tab页(示例只注册了 mine order home 任选一个填入)</text>
</view>
<view>
<input style="height: 50px; border:1px solid grey;margin: 5px 0;" v-model="addr"
placeholder="输入跳转tabbar key" />
<button type="warn" @click="tz">跳转tab页</button>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref, computed } from 'vue'
import { stringToBase64, base64ToString, ReqApi } from "@/uni_modules/sunrains-request"
import { Response, FrontRequestVo } from "@/uni_modules/sunrains-common-type"
import { CustFailError, getComErrorInfo } from "@/uni_modules/sunrains-common-err"
import { pageToTab } from "@/uni_modules/sunrains-tabbar-pro/utssdk/outtypes"
onMounted(() => {
console.log('【组件挂载====detail===】')
})
onUnmounted(() => {
console.log('【组件销毁====detail===】')
})
const addr = ref("")
function tz() {
if (addr.value.length < 1) {
uni.showToast({
title: '请输入跳转的tabbar key'
});
} else {
pageToTab(addr.value)
}
}
function fh() {
uni.navigateBack()
}
let priKey = "4a4a1d48fc284fe2fc43970641880554aed2f69fdfbea63257ea417af4e65802"
let pubKey = "0460e86263ec52b38a3da24c7a605055d14f8aa5c7855e4f4e19819f4f8a5b72181afd7aa4ab19255eb871eaedaba30fa18cd5c71693d3d76b030a04969bd1edfe"
const BASEURL = "http://112.124.32.215:9080/sunrainsapi"
type IRootType = {
name : string;
age : number;
}
type Builds = {
buildingNo : string,
sortNum : number,
buildAreaId : string,
id : string
}
async function req() {
let data : UTSJSONObject = {
name: "张三",
age: 18
}
try {
let vo : FrontRequestVo = {
method: 'GET',
url: BASEURL + "/test/get/cs1",
data: data,
header: null,
reqFlag: "void",
priKey: priKey,
pubKey: pubKey,
//method 为POST时 不能为null
contentType: "urlencoded",
timeout: null,
//当为上传文件时 文件路径参数不能为空
filePathParamName: null
}
const res = await ReqApi(vo)
console.log("####reqvoid==", res.data)
// console.log("####==",res)
} catch (err) {
uni.showToast({
title: err.message ?? "请求异常",
icon: "error"
})
console.log("-----", err)
return
};
}
//"sign"|"sm4Encrypt"|"signwithenSM2-Sm4Encrypt"|"void";
async function reqSm2() {
let data : UTSJSONObject = {
name: "张三",
age: 18
}
try {
let vo : FrontRequestVo = {
method: 'GET',
url: BASEURL + "/test/get/cs1",
data: data,
header: null,
reqFlag: "sign",
priKey: priKey,
pubKey: pubKey,
//method 为POST时 不能为null
contentType: "urlencoded",
timeout: null,
//当为上传文件时 文件路径参数不能为空
filePathParamName: null
}
const res = await ReqApi(vo)
console.log("####reqSm2==", res.data)
} catch (err) {
uni.showToast({
title: err.message ?? "请求异常",
icon: "error"
})
//#ifndef APP-ANDROID
const errMsg = (err as any).errMsg ?? "未知错误";
const errCode = (err as any).errCode ?? -1;
console.log('标准化错误码:', errMsg);
console.log('标准化错误信息:', errCode);
//#else
if (err instanceof UniError) {
let sa = err as UniError
console.log('sa==:', sa);
}
//#endif
console.log("-----", err)
return
};
}
async function reqSm4() {
let data : UTSJSONObject = {
name: "张三",
age: 18
}
try {
let vo : FrontRequestVo = {
method: 'POST',
url: BASEURL + "/test/post/cs1",
data: data,
header: null,
reqFlag: "sm4Encrypt",
priKey: priKey,
pubKey: pubKey,
//method 为POST时 不能为null
contentType: "urlencoded",
timeout: null,
//当为上传文件时 文件路径参数不能为空
filePathParamName: null
}
const res = await ReqApi(vo)
console.log("####reqSm4==", res.data)
} catch (err) {
console.log("####reqSm4 err==", err)
uni.showToast({
title: err.message ?? "",
icon: "error"
})
return
};
}
async function reqSm2Sm4() {
let data : UTSJSONObject = {
name: "张三",
age: 18
}
try {
let vo : FrontRequestVo = {
method: 'POST',
url: BASEURL + "/test/post/cs1",
data: data,
header: null,
reqFlag: "signwithenSM2-Sm4Encrypt",
priKey: priKey,
pubKey: pubKey,
//method 为POST时 不能为null
contentType: "urlencoded",
timeout: null,
//当为上传文件时 文件路径参数不能为空
filePathParamName: null
}
const res = await ReqApi(vo)
console.log("####reqSm2Sm4==", res.data)
} catch (err) {
console.log("-----", err)
return
};
}
const orderId = ref<string>('')
const orderStatus = ref<string>('')
const content = ref<string>('')
const sbase64 = computed(() => {
return stringToBase64(content.value)
})
const base64yostr = computed(() => {
return base64ToString(sbase64.value)
})
onLoad((options) => {
const opts = options as UTSJSONObject
const id = options?.["orderId"] as string | null
const status = options?.["status"] as string | null
if (id != null) {
orderId.value = id
}
if (status != null) {
orderStatus.value = status
}
console.log(`接收算法参数:ID=${orderId.value},状态=${orderStatus.value}`)
})
const goBack = () => {
uni.navigateBack()
}
function init() {
// uni.stopPullDownRefresh()
// console.log('stop onPullDownRefresh=====');
}
// onPullDownRefresh(() => {
// console.log('onPullDownRefresh=====');
// init()
// })
function refresh() {
uni.removeStorageSync("LOGINTABBARITEMS")
// uni.startPullDownRefresh({
// success:()=>{
// console.log("1111")
// }
// });
// init()
}
</script>
<style scoped>
.detail-root {
/* flex: 1;
display: flex;
flex-direction: column; */
background-color: #fff;
}
.status-bar {
height: 44px;
background-color: #ffffff;
}
.detail-header {
height: 44px;
background-color: #fff;
flex-direction: row;
align-items: center;
padding-left: 15px;
padding-right: 15px;
border-bottom-width: 1px;
border-bottom-style: solid;
border-bottom-color: #eee;
}
.back-icon {
font-size: 18px;
color: #007aff;
margin-right: 10px;
}
.detail-title {
font-size: 16px;
font-weight: bold;
color: #333;
}
.detail-content {
flex: 1;
padding: 20px;
}
.detail-item {
flex-direction: row;
margin-bottom: 20px;
align-items: center;
}
.label {
font-size: 15px;
color: #666;
width: 80px;
}
.value {
font-size: 15px;
color: #333;
font-weight: bold;
}
.detail-desc {
margin-top: 30px;
}
.com {
display: flex;
align-items: center;
margin: 10px 0;
}
.com1 {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
border-radius: 5px;
margin: 10px 10px;
background-color: #64e4e0
}
.con {
margin: 10px 0;
padding: 10px;
background-color: #e3eda1;
}
.btn {
margin: 5px;
}
</style>
7 拓展底部tabbar类型,(切换、弹出、进入)页面
/**
* path 组件或页面路径 当类型为 page 时不可为空,其它传空字符串即可
* tabType 类型 tabPage:tab页面 tabPop:弹窗组件 page:普通页面
*/
export type TabItemType = {
key : string;
path : string;
tabType : string;
}
注: 类型为 tabPop 打开页面 可右滑手势(当手机开启右滑手势时)关闭、 或点击虚拟返回按键关闭 或 页面中调用方法 closeTabPop()关闭
closeTabPop()关闭方法导入 import { closeTabPop} from "@/uni_modules/sunrains-tabbar-pro/utssdk/outtypes"
8 多层级tabbar,可返回上一层,返回首层
toNextTabItems:下一层级的tabbar 返回方法 goBack() 返回上一层 传 back 返回首层 传 backBase
<template>
<view class="box">
<text class="txt">AAAAA</text>
</view>
<view class="order-item">
<button @click="nextTabItems()" type="warn">
点击进入下一层级tabbar(显示指定f页面)(d、e、f)
</button>
</view>
<view class="order-item">
<button @click="back('backBase')" type="warn">
返回首页
</button>
</view>
<view class="order-item">
<button @click="back('back')" type="warn">
返回上一层
</button>
</view>
</template>
<script setup>
import {
toNextTabItems, RefreshTabbarType, goBack
} from '@/uni_modules/sunrains-tabbar-pro/utssdk/outtypes'
function back(type : string) {
goBack(type)
}
const nextTabItems = () => {
let params : RefreshTabbarType = {
tabItems: [
{
key: 'D',
path: "",
fontSize: 20,
fontColor: "white",
activeFontColor: "red",
fontWeight: "bold",
name: 'D',
icon: '',
activeIcon: '',
iconW: 24,
iconH: 24,
tabType: "tabPage"
},
{
key: 'E',
path: "",
fontSize: 20,
fontColor: "white",
activeFontColor: "red",
fontWeight: "bold",
name: 'E',
icon: '',
activeIcon: '',
iconW: 24,
iconH: 24,
tabType: "tabPage"
},
{
key: 'F',
path: "",
fontSize: 20,
fontColor: "white",
activeFontColor: "red",
fontWeight: "bold",
name: 'F',
icon: '',
activeIcon: '',
iconW: 24,
iconH: 24,
tabType: "tabPage"
}
],
type: "toNext",
indexKey: "F"
}
toNextTabItems(params)
}
</script>
<style>
</style>
9. tabbar与tab页之前事件驱动
下面示例主要展示: tabbar与tab页之间(页面刷新、返回顶端)事件驱动 1:当页面在顶端时(未向下滑动到阈值)点击事件驱动tabbar会自动下拉刷新 2:当页面向下滑动到设置阈值,tabbar图标会变化,此时再点击图标会返回到顶端
核心点:
1: tab页监听tabbar的点击事件(uni.$off(${EMIT_TABBAR_SEND}-key))
2: tab页通过tabSendIconEvent方法向tabbar发送图标变动事件
<template>
<scroll-view class="mine-page" direction="vertical" show-scrollbar="false" enable-back-to-top="true"
refresher-enabled="true" refresher-default-style="none" refresher-background="rgba(228, 217, 104, 1.0)"
:refresher-triggered="data.refreshing2" refresher-max-drag-distance="200px"
@refresherpulling="onRefresherpulling2" @refresherrefresh="onRefresherrefresh2"
@refresherrestore="onRefresherrestore2" :scroll-top="scrollTop" @scroll="" <!-- #ifdef APP-ANDROID -->
:scroll-with-animation="true"
<!-- #endif -->
>
<uni-refresh-box slot="refresher" :pulling-distance="data.pullingDistance2" :refreshing="data.refreshing2"
loading-class="loading-dark" text-class="uni-text-class-buildin"
style="flex-direction: column;height: 46px;padding-top: 6px;" pulling-text="继续下拉可刷新" loosing-text="释放后会刷新"
loading-text="加载中..." />
<view class="page-title">
<text class="text">tabbar与tab页之间(页面刷新、返回顶端)事件驱动\n
1:当页面在顶端时(未向下滑动到阈值)点击事件驱动tabbar会自动下拉刷新\n
2:当页面向下滑动到设置阈值,tabbar图标会变化,此时再点击图标会返回到顶端
</text>
</view>
<view v-for="i in listData" :key="i" class="item">
<text class="text">{{ i }}</text>
</view>
</scroll-view>
</template>
<script setup lang="uts">
import { ref, onMounted, onUnmounted } from 'vue'
import {tabSendIconEvent, EMIT_TABBAR_SEND} from '@/uni_modules/sunrains-tabbar-pro/utssdk/outtypes'
const scrollTop = ref(0)
const isExecuting = ref(false)
let isAvtive = false
const listData = ref([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
const data = reactive({
refreshing2: false,
pullingDistance2: 0
})
function onRefresherpulling2(e : RefresherEvent) {
data.pullingDistance2 = e.detail.dy
}
const refreshing = ref(false)
function onRefresherrefresh2() {
if (data.refreshing2 == true || isExecuting.value) {
return
}
isExecuting.value = true
data.refreshing2 = true
console.log('触发刷新')
setTimeout(() => {
data.refreshing2 = false
isExecuting.value = false
console.log('刷新完成')
}, 1500)
}
function onRefresherrestore2() {
data.pullingDistance2 = 0
}
function onRefresherabort2() {
data.pullingDistance2 = 0
}
function (event : UniScrollEvent) {
let num = event.detail.scrollTop
if (num > 0) {
scrollTop.value = num
}
if (scrollTop.value > 170) {
if (!isAvtive) {
tabSendIconEvent(true)
}
isAvtive = true
} else {
if (isAvtive) {
tabSendIconEvent(false)
}
isAvtive = false
}
}
const tabbarEvent = () => {
if (!isAvtive) {
onRefresherrefresh2()
} else {
scrollTop.value = 0
}
}
onMounted(() => {
console.log('【组件挂载====XLSX##===】')
uni.$off(`${EMIT_TABBAR_SEND}-XLSX`)
uni.$on(`${EMIT_TABBAR_SEND}-XLSX`, tabbarEvent)
})
onUnmounted(() => {
console.log('【组件销毁====XLSX===】')
})
</script>
<style scoped lang="scss">
.mine-page {
height: 99%;
width: 100%;
}
.item {
padding: 20px;
border-bottom: 1px solid #eee;
background-color: #f1c8d1;
margin: 15px;
height: 200px;
display: flex;
align-items: center;
justify-content: center;
.text {
font-size: 50px;
}
}
.page-title {
margin: 15px;
display: flex;
align-items: center;
justify-content: center;
background-color: #eff1c5;
border-radius: 10px;
.text {
margin: 10px;
color: black;
font-size: 20px;
font-weight: bold;
}
}
</style>
10. mine.uvue示例代码
该示例包含 动态设置tabbar、主题切换、数字角标 功能
<template>
<view class = "content">
<scroll-view direction="vertical" class="mine-page" show-scrollbar="false">
<view class="page-title">
<text style="color:black;font-size: 26px;font-weight: bold;">动态设置中心</text>
</view>
<view class="tabbar">
<view class="tabbar-item">
<text class="item-text">tabbar设置</text>
<button class="tabbar-btn" @click="refresh1">动态tabbar(首页、我的、事件驱动)</button>
<button class="tabbar-btn" @click="refresh2">动态tabbar(算法、首页、我的、弹出详情、进入详情)</button>
</view>
<view class="tabbar-item">
<text class="item-text">设置角标(示例只注册了 mine order home 任选一个填入)</text>
<input class="input-item" v-model="tabbar" placeholder="请输入需要设置角标的tabbar key" />
<input class="input-item" v-model="badge" placeholder="请输入角标" />
<button class="tabbar-btn" @click="setBadge">确定</button>
</view>
<view class="tabbar-item">
<text class="item-text">主题切换设置</text>
<view class="zt">
<button class="tabbar-btn1" @click="theme">主题1</button>
<button class="tabbar-btn1" @click="theme2">主题2</button>
<button class="tabbar-btn1" @click="theme3">主题3</button>
<button class="tabbar-btn1" @click="clear()">登 出</button>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup lang="uts">
import { ref, onMounted, onUnmounted } from 'vue'
import {loginOut} from '@/tabbar-config.uts'
import {
TabItemType, CustomThemeType, TabbarIconType, TabbarStyleType, NavBarConfigType,
setTabBadge, setTabbarColorHeight, refreshTabbar, setTabPageTheme, closeTabPop, clearStorage, RefreshTabbarType
} from '@/uni_modules/sunrains-tabbar-pro/utssdk/outtypes'
onMounted(() => {
console.log('【组件挂载====mine===】')
})
onUnmounted(() => {
console.log('【组件销毁====mine===】')
})
function clear() {
loginOut()
// clearStorage("all")
}
const bgColor = ref<string>('pink')
const tabHeight = ref<string>('240')
const badge = ref<string>('0')
// tab 选项配置
const tabbar = ref<string>("")
const selectedTab = ref<string>('mine')
const selectedTabIndex = ref<number>(0)
function setBadge() {
//动态设置指定tabbar 角标
const badgeNum = parseInt(badge.value)
if (isNaN(badgeNum)) {
uni.showToast({
title: '请输入有效数字',
icon: 'none'
})
return
}
setTabBadge(tabbar.value, badgeNum)
uni.showToast({
title: `已设置 ${tabbar.value} 角标为 ${badgeNum}`,
icon: 'success'
})
}
function refresh1() {
console.log("动态tabbar(我的)")
let params : RefreshTabbarType = {
tabItems: [
{
key: 'home',
path: "",
fontSize: 24,
fontColor: "black",
activeFontColor: "white",
fontWeight: "bold",
name: '首页',
icon: '/static/tab/main1.png',
activeIcon: '/static/tab/main1_active.png',
eventIcon: "",
iconW: 48,
iconH: 48,
tabType: "tabPage",
remount:false,
enableEvent: false
},
{
key: 'mine',
path: "",
fontSize: 24,
fontColor: "black",
activeFontColor: "white",
fontWeight: "bold",
name: '我的',
icon: '/static/tab/main3.png',
activeIcon: '/static/tab/main3_active.png',
eventIcon: "",
iconW: 48,
iconH: 48,
tabType: "tabPage",
remount:true,
enableEvent: false
},
{
key: 'XLSX',
path: "",
fontSize: 24,
fontColor: "black",
activeFontColor: "white",
fontWeight: "bold",
name: '事件驱动',
icon: '/static/难过.png',
activeIcon: '/static/微笑.png',
eventIcon: "/static/爱心.png",
iconW: 48,
iconH: 48,
tabType: "tabPage",
remount:false,
enableEvent: true
}
],
type: "refreshBase"
}
refreshTabbar(params);
}
function refresh2() {
console.log("动态tabbar(我的、算法、首页、弹出详情、进入详情)")
let params : RefreshTabbarType = {
tabItems: [
{
key: 'order',
path: "",
fontSize: 24,
fontColor: "black",
activeFontColor: "white",
fontWeight: "bold",
name: '算法',
icon: '/static/tab/main2.png',
activeIcon: '/static/tab/main2_active.png',
eventIcon: "",
iconW: 48,
iconH: 48,
tabType: "tabPage",
remount:false,
enableEvent: false
},
{
key: 'home',
path: "",
fontSize: 24,
fontColor: "black",
activeFontColor: "white",
fontWeight: "bold",
name: '首页',
icon: '/static/tab/main1.png',
activeIcon: '/static/tab/main1_active.png',
eventIcon: "",
iconW: 48,
iconH: 48,
tabType: "tabPage",
remount:false,
enableEvent: false
},
{
key: 'mine',
path: "",
fontSize: 24,
fontColor: "black",
activeFontColor: "white",
fontWeight: "bold",
name: '我的',
icon: '/static/tab/main3.png',
activeIcon: '/static/tab/main3_active.png',
eventIcon: "",
iconW: 48,
iconH: 48,
tabType: "tabPage",
remount:true,
enableEvent: false
},
{
key: 'detail',
path: "",
fontSize: 24,
fontColor: "red",
activeFontColor: "",
fontWeight: "bold",
name: '弹出详情',
icon: '/static/弹出详情.png',
activeIcon: '',
eventIcon: "",
iconW: 48,
iconH: 48,
tabType: "tabPop",
remount:false,
enableEvent: false
},
{
key: 'detail',
path: "/pages/detail/detail",
fontSize: 24,
fontColor: "red",
activeFontColor: "",
fontWeight: "bold",
name: '进入详情',
icon: '/static/详情.png',
activeIcon: '',
eventIcon: "",
iconW: 48,
iconH: 48,
tabType: "page",
remount:false,
enableEvent: false
}
],
type: "refreshBase",
indexKey: "mine"
}
refreshTabbar(params);
}
function theme() {
//主题背景类型
let bgType = "IMG"
//背景 如果是图片传图片路径 颜色则传 具体颜色
let bg : string = "/static/2.png"
// let bg:string = "black"
let navBarConfig : NavBarConfigType = {
showTitle: true,
titleFontSize: 34,
titleFontWeight: 'bold',
titleColor: '#FFA500',
navBarBackgroundColor: "rgba(191, 191, 191, 0.5)",
navBarBackgroundImage: "",
navBarHeight: 90
}
let tabbarIcon : TabbarIconType = {
key: "mine",
icon: "https://gimg3.baidu.com/search/src=https%3A%2F%2Fpic.rmb.bdstatic.com%2Fbjh%2Fuser%2F779083e57f84a4ce5345b17aaf7f8459.jpeg&refer=http%3A%2F%2Fwww.baidu.com&app=2021&size=r1,1&n=0&g=4&er=404&q=100&maxorilen2heic=2000000?sec=1782483600&t=4feca8b5a1149e3ed0f28ee030f767b4",
activeIcon: "/static/tab/main3_active.png",
eventIcon: "",
iconW: 48, iconH: 48,
fontSize: 24,
fontColor: "white",
activeFontColor: "green",
fontWeight: "bold"
}
let tabbarIcon1 : TabbarIconType = {
key: "home",
icon: "",
activeIcon: "",
eventIcon: "",
iconW: 0, iconH: 0,
fontSize: 24,
fontColor: "white",
activeFontColor: "green",
fontWeight: "bold"
}
let tabbarIcon3 : TabbarIconType = {
key: "XLSX",
icon: "/static/tab/main2.png",
activeIcon: "/static/tab/main2_active.png",
eventIcon: "",
iconW: 48, iconH: 48,
fontSize: 24,
fontColor: "white",
activeFontColor: "red",
fontWeight: "bold"
}
let tabbarIcons : Map<string, TabbarIconType> = new Map();
tabbarIcons.set("mine", tabbarIcon)
tabbarIcons.set("home", tabbarIcon1)
tabbarIcons.set("XLSX", tabbarIcon3)
let tabbarStyle : TabbarStyleType = {
tabbarHeight: 120,
bgColor: "rgba(21, 20, 31, 0.8)",
tabbarIcons: tabbarIcons
}
let theme : CustomThemeType = {
bgType: bgType,
bg: bg,
navBarConfig: navBarConfig,
tabbarStyle: tabbarStyle
}
setTabPageTheme(theme)
}
function theme2() {
//主题背景类型
let bgType = "IMG"
//背景 如果是图片传图片路径 颜色则传 具体颜色
let bg : string = "/static/sm.jpg"
// let bg:string = "black"
let navBarConfig : NavBarConfigType = {
showTitle: true,
titleFontSize: 34,
titleFontWeight: 'bold',
titleColor: '#0c0c0c',
navBarBackgroundColor: "",
navBarBackgroundImage: "",
navBarHeight: 90
}
let tabbarIcon : TabbarIconType = {
key: "mine",
icon: "/static/jqr.gif",
activeIcon: "/static/jqr.gif",
eventIcon: "",
iconW: 160, iconH: 160,
fontSize: 0,
fontColor: "green",
activeFontColor: "red",
fontWeight: "bold"
}
let tabbarIcon3 : TabbarIconType = {
key: "order",
icon: "/static/tab/main2.png",
activeIcon: "/static/tab/main2_active.png",
eventIcon: "",
iconW: 48, iconH: 48,
fontSize: 24,
fontColor: "green",
activeFontColor: "red",
fontWeight: "bold"
}
let tabbarIcon1 : TabbarIconType = {
key: "home",
icon: "/static/sy1.png",
activeIcon: "/static/sy.png",
eventIcon: "",
iconW: 48, iconH: 48,
fontSize: 24,
fontColor: "green",
activeFontColor: "red",
fontWeight: "bold"
}
let tabbarIcons : Map<string, TabbarIconType> = new Map();
tabbarIcons.set("mine", tabbarIcon)
tabbarIcons.set("home", tabbarIcon1)
tabbarIcons.set("order", tabbarIcon3)
let tabbarStyle : TabbarStyleType = { tabbarHeight: 120, bgColor: "rgba(21, 20, 31, 0.4)", tabbarIcons: tabbarIcons }
let theme : CustomThemeType = { bgType, bg, navBarConfig, tabbarStyle }
setTabPageTheme(theme)
console.log("theme=",theme)
}
function theme3() {
//主题背景类型
let bgType = "IMG"
//背景 如果是图片传图片路径 颜色则传 具体颜色
let bg : string = "/static/端午3.png"
// let bg:string = "black"
let navBarConfig : NavBarConfigType = {
showTitle: true,
titleFontSize: 34,
titleFontWeight: 'bold',
titleColor: '#0c0c0c',
navBarBackgroundColor: "",
navBarBackgroundImage: "",
navBarHeight: 90
}
let tabbarIcon : TabbarIconType = {
key: "mine",
icon: "/static/aj.png",
activeIcon: "/static/aj1.png",
eventIcon: "",
iconW: 48, iconH: 48,
fontSize: 24,
fontColor: "white",
activeFontColor: "red",
fontWeight: "bold"
}
let tabbarIcon1 : TabbarIconType = {
key: "home",
icon: "/static/sy1.png",
activeIcon: "/static/sy.png",
eventIcon: "",
iconW: 48, iconH: 48,
fontSize: 24,
fontColor: "white",
activeFontColor: "red",
fontWeight: "bold"
}
let tabbarIcon3 : TabbarIconType = {
key: "order",
icon: "/static/tab/main2.png",
activeIcon: "/static/tab/main2_active.png",
eventIcon: "",
iconW: 48, iconH: 48,
fontSize: 24,
fontColor: "white",
activeFontColor: "red",
fontWeight: "bold"
}
let tabbarIcons : Map<string, TabbarIconType> = new Map();
tabbarIcons.set("mine", tabbarIcon)
tabbarIcons.set("home", tabbarIcon1)
tabbarIcons.set("order", tabbarIcon3)
let tabbarStyle : TabbarStyleType = { tabbarHeight: 120, bgColor: "rgba(10, 13, 31, 0.8)", tabbarIcons: tabbarIcons }
let theme : CustomThemeType = { bgType, bg, navBarConfig, tabbarStyle }
setTabPageTheme(theme)
}
</script>
<style scoped lang="scss">
.content{
width: 100%;
height: 100%;
}
.mine-page {
height: 99.5%;
// border: 1px solid red;
// background: rgba(489, 235, 481, 0.5);
border-radius: 5px;
padding: 5px 5px 0 5px;
margin: 1px;
}
.page-title {
margin-bottom: 15px;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100px;
background: cadetblue;
border-radius: 10px;
}
.tabbar {
width: 100%;
display: flex;
flex-direction: column;
.tabbar-item {
background: rgba(221, 483, 485, 0.6);
margin: 10px 0;
border-radius: 10px;
.tabbar-btn {
margin: 15px;
border-radius: 8px;
background: #6c6de3;
border: 1px solid #e5e5e5;
padding: 16px 40px;
font-size: 16px;
}
.zt {
display: flex;
flex-direction: row;
flex-wrap: wrap;
.tabbar-btn1 {
width: 50%;
margin: 10px auto;
border-radius: 8px;
background: #6c6de3;
border: 1px solid #e5e5e5;
padding: 16px 40px;
font-size: 16px;
}
}
.tabbar-btn:last-child {
margin-bottom: 0;
}
.item-text {
font-size: 20px;
margin: 10px auto;
}
.input-item {
height: 45px;
border: 1px solid #ccc;
border-radius: 6px;
padding-left: 10px;
background: #fff;
margin: 10px;
padding-left: 20px;
}
}
}
</style>
11. 同层级tab页跳转tab页
调用方法 tabToTab 参数 同层级 tabbar的key值 必须两个tab页类型都是 tabPage
⚠️ 常见问题
Q1: 为什么小程序端需要单独配置?
A: 微信小程序不支持动态组件渲染,必须静态声明所有可能使用的组件。
Q2: 动态 Tab 刷新失败怎么办?
A: 检查以下几点:
- 组件是否在 App.uvue初始化逻辑 中正确注册
- 是否正确使用了
getComponentRegistryByKey.get("key")获取组件 - TabItemType 的参数是否完整且类型正确
Q3: 如何设置数字角标?
A: 使用 setTabBadge(key, badgeNum) 即可,详见第 4 章。
Q4: 角标设置后不显示怎么办?
A: 检查以下几点:
- badge 值是否大于 0(0 或负数不显示)
- tab key 是否正确(必须与 TabItemtype 的 key 一致)
- 是否重新赋值了整个数组(直接修改对象属性不会触发响应式)
Q5: 退出登录如何清除 tabbar相关缓存
A: 调用 clearStorage 方法
import {clearStorage} from '@/uni_modules/sunrains-tabbar-pro/utssdk/outtypes'
/**
* 清除tabbar相关缓存
* all 所有
* theme 主题
* tabbarItems 所有tabbar
* badge 角标
*/
/**
* 清除tabbar相关缓存
* all 所有
* theme 主题
* tabbarItems 所有tabbar
* badge 角标
*/
export function clearStorage(type:string){
switch (type){
case "theme":
uni.removeStorageSync(STORE_CUSTOM_THEME)
break;
case "tabbarItems":
uni.removeStorageSync(STORE_LOGIN_TABBAR_ITEMS)
break;
case "badge":
uni.removeStorageSync(STORE_TABBAR_BADGES)
break;
default:
uni.removeStorageSync(STORE_CUSTOM_THEME)
uni.removeStorageSync(STORE_LOGIN_TABBAR_ITEMS)
uni.removeStorageSync(STORE_TABBAR_BADGES)
uni.removeStorageSync(STORE_BASE_INDEX_KEY)
}
}

收藏人数:
购买源码授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 29
赞赏 0
下载 12494988
赞赏 1939
赞赏
京公网安备:11010802035340号