uniapp x 动态Tabbar(切换无闪烁)+动角标+主题切换+自定义tabbar页面导航栏样式设置 支持服务端动态配置根据角色动态设置Tabbar

sunrains-tabbar 自定义 TabBar 插件使用指南

点击体验h5端

点击查看安卓端录屏效果

📋 目录

  • 1. 基础配置

  • 2. pages.json 配置

  • 3. 动态配置 TabBar

  • 4. 数字角标功能

  • 5. 小程序端特殊配置

  • 6. 主题配置

  • 7. page页跳转自定义tab页

  • 8. 拓展底部tabbar类型,(切换、弹出、进入)页面


1. 基础配置

uts 复制代码
App.uvue onLaunch 初始化
 import {initDefaultTabItems} from '@/uni_modules/sunrains-tabbar/tabbar-config.uts'
		onLaunch(() => {
		console.log('App Launch')
		initDefaultTabItems()
		}

1.1 配置 tabbar-config.uts 文件

在插件根目录 tabbar-config.uts 文件中,配置注册全局tab组件和导航栏设置。

完整示例:

uts 复制代码
import { setNavbarConfig, NavBarConfig, registerGlobalComponent, setDefaultTabItems, TabItem } from '@/uni_modules/sunrains-tabbar/utssdk/types.uts'
import { getStoreLoginItems,storeLoginItems } from './utssdk/handle'
//导入所有自定义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'

//注册所有需要切换的tab页或需要弹出的页面  即类型为 tabPage:tab页面  tabPop:弹窗组件
registerGlobalComponent('home', Recommend)
registerGlobalComponent('order', Order)
registerGlobalComponent('mine', Mine)
registerGlobalComponent('detail', Detail)

// 2. 配置导航栏(不设置会使用默认配置)
setNavbarConfig(new NavBarConfig(true, 34, 'bold', '#333333', '#ffffff', "", 88))


//初始化默认tabbar区域按钮
export function initDefaultTabItems(){
	/**
	 *
	 * 3. 设置默认 Tab 列表(至少设置一个固定的,也可以全部设置,其它可通过请求服务端接口动态配置),
	 * 或通过网络请求初始化 游客 显示哪些  有 角色的 按角色 初始化
	 * App.uvue onLaunch 初始化
	  import {initDefaultTabItems} from '@/uni_modules/sunrains-tabbar/tabbar-config.uts'
		onLaunch(() => {
		console.log('App Launch')
		initDefaultTabItems()
		}
	 */
	let home = new TabItem('home',"", 12, "red", "yellow", "bold", '首页', '/static/tab/main3.png', '/static/tab/main3_active.png',24,24,"tabPage")
	let mine = new TabItem('mine',"", 12, "red", "yellow", "bold", '我的', '/static/tab/main3.png', '/static/tab/main3_active.png',24,24,"tabPage")

	let items = getStoreLoginItems();
	//判断是否登录
	if(false || items != null){
		setDefaultTabItems(items)
	}else{
		setDefaultTabItems([
			home,mine
		])
		storeLoginItems([home,mine])
	}

}

关键步骤说明:

  1. 导入组件:将所有需要作为 Tab 的页面组件导入
  2. 注册组件 :使用 registerGlobalComponent 注册每个组件(第一个参数为唯一标识)
  3. 配置导航栏:可选配置,根据项目需求调整
  4. 设置默认 Tab:至少配置一个固定 Tab,其余可动态添加

2. pages.json 配置

2.1 必需配置

必须在 pages.json 中配置自定义 TabBar 入口页面(必须放在第一个位置),tab页无需在pages.json中配置:

json 复制代码
{
  "path": "uni_modules/sunrains-tabbar/index",
  "style": {
    "navigationStyle": "custom"
  }
}

2.2 完整示例

json 复制代码
{
	"pages": [ 
		{
		  "path": "uni_modules/sunrains-tabbar/utssdk/index",
		  "style": {
		    "navigationStyle": "custom"
		  }
		},
		{
		  "path": "pages/detail/detail",
		  "style": {
		    "navigationBarTitleText": "详情"
		  }
		}
	],
	"globalStyle": {
		"navigationBarTextStyle": "black",
		"navigationBarTitleText": "uni-app x",
		"navigationBarBackgroundColor": "#F8F8F8",
		"backgroundColor": "#F8F8F8"
	},
	"uniIdRouter": {}
}

注意事项:

  • 自定义 TabBar 入口页面必须配置在 pages 数组的第一位
  • 所有 Tab 页面不需要在 pages 中声明
  • navigationStyle 设置为 "custom" 以隐藏原生导航栏

3. 动态配置 TabBar

3.1 使用场景

当需要根据用户权限、服务端配置等动态调整 TabBar 时,可以在任意页面触发刷新。

3.2 实现示例

以下面文档 mine.uvue 页面为例:

关键点:

  • 使用 refreshTabbar方法触发 TabBar 刷新
  • 确保所有动态 Tab 对应的组件已在 tabbar-config.uts 中注册

4. 数字角标功能

4.1 功能说明

支持为任意 Tab 设置数字角标,用于显示未读消息数、待处理事项等。

特性:

  • ✅ 动态设置/更新角标
  • ✅ 超过 99 自动显示 "99+"
  • ✅ 角标为 0 或 null 时不显示
  • ✅ 响应式更新,立即生效

4.2 使用方法

方法一:通过事件设置(推荐)

在任意页面通过 调用 setTabBadge 方法:

typescript 复制代码
import { setTabBadge} from '@/uni_modules/sunrains-tabbar/utssdk/noticetab.uts'
// 设置算法 tab 的角标为 5
setTabBadge("order",5)
// 清除角标(设置为 0)
setTabBadge("order",0)
// 设置超过 99 显示 99+
setTabBadge("order",150)
方法二:初始化时设置

在创建 TabItem 时传入 badge 参数:

typescript 复制代码
import { TabItem } from '@/uni_modules/sunrains-tabbar/utssdk/types.uts'

// 带角标的 tab
new TabItem(
  'order', 
  '算法', 
  '/static/tab/main2.png', 
  '/static/tab/main2_active.png'
  10  // badge 参数
)

// 不带角标的 tab
new TabItem(
  'home', 
  '首页', 
  '/static/tab/main1.png', 
  '/static/tab/main1_active.png'
)

4.3 完整示例

以 文档后面 mine.uvue 页面为例,实现动态设置角标功能:

4.4 实际应用场景

场景 1:算法未读数
typescript 复制代码
// 从服务端获取未读算法数
async function loadUnreadOrderCount() {
  const res = await getOrderCount()
  setTabBadge("order",res.data.count)
}

// 页面加载时调用
onShow(() => {
  loadUnreadOrderCount()
})
场景 2:消息通知
typescript 复制代码
// WebSocket 收到新消息
websocket.onMessage((msg) => {
  if (msg.type === 'new_message') {
    const currentBadge = getCurrentBadge('message')
	setTabBadge("newMessage",currentBadge + 1)
  }
})
场景 3:购物车数量
typescript 复制代码
// 添加商品到购物车后更新角标
function addToCart(product: Product) {
  cartItems.push(product)
  setTabBadge("cart",cartItems.length)
}

5. 小程序端特殊配置

4.1 配置 tab-content-renderer.uvue

注意: 仅在需要支持微信小程序时需要配置,App 端可忽略此步骤。

uni_modules/sunrains-tabbar/tab-content-renderer.uvue 中配置:

vue 复制代码
<<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">
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>

配置说明:

  1. 条件编译 :使用 #ifndef MP-WEIXIN#ifdef MP-WEIXIN 区分平台
  2. App 端 :使用 <component :is="..."> 动态渲染组件
  3. 小程序端:必须静态导入并声明所有可能的 Tab 组件
  4. 导入位置 :在 #ifdef MP-WEIXIN 块内导入组件

6. 主题配置

6.1 主题功能说明

插件支持自定义 TabBar 的主题样式,支持网络背景图、本地图片背景图、纯颜色背景(支持rgba透明)、导航栏、tabbar区域背景、图标大小、图标(支持网络图标)、文字颜色、文字大小、等属性 满足不同项目的视觉需求。

主题特性:

  • ✅ 支持全局主题配置
  • ✅ 支持动态切换主题
  • ✅ 支持自定义主题参数

6.2 初始化时配置主题

tabbar-config.uts 文件中配置主题:

typescript 复制代码
import { 
  setNavbarConfig, 
  NavBarConfig, 
  registerGlobalComponent, 
  setDefaultTabItems, 
  TabItem,
  setTabBarTheme,
  TabBarTheme
} from '@/uni_modules/sunrains-tabbar/types.uts'
import { setTabPageTheme} from '@/uni_modules/sunrains-tabbar/utssdk/noticetab.uts'

let bgType : BgType = "IMG"
//背景 如果是图片传图片路径 颜色则传 具体颜色
let bg : string = "/static/2.png"
//配置导航栏(可选,不设置会使用默认配置)
let navBarConfig : NavBarConfig = new NavBarConfig(
    true, // 是否显示导航栏
    34,  // 字体大小
    'bold',  // 字体粗细
    '#FFA500', // 文字颜色
    '',// 背景颜色
    "", //背景图片(支持网络图片)
    90) // 导航栏高度


let tabbarIcon = new TabbarIcon(
    "mine",//自定义组件唯一标识
    //非选中图标
    "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=1781283600&t=4feca8b5a1149e3ed0f28ee030f767b4",
   //选中图标
    "/static/tab/main3_active.png",
	24,//图标宽 单位 px
	24,//图标高 单位 px
   //文字颜色
    12,
    //非选中文字大小
    "green",
    //选择文字颜色
    "white",
    //选择文字粗细
    "bold"
)

let tabbarIcons : Map<string,TabbarIcon> = new Map();
tabbarIcons.set("mine",tabbarIcon)

let tabbarStyle : TabbarStyle = new TabbarStyle(
    //tabbar区域高度
    120,
    //tabbar区域背景
    "rgba(21, 20, 31, 0.8)",
    //tabbar图标文字样式
    tabbarIcons)

let theme = new CustomTheme(bgType, bg, navBarConfig, tabbarStyle);
setTabPageTheme(theme)

6.3 动态修改主题

在任意页面通过调用 setTabPageTheme 方法动态修改主题:

typescript 复制代码
import { setTabPageTheme} from '@/uni_modules/sunrains-tabbar/utssdk/noticetab.uts'
// 动态修改背景色和选中颜色
let theme = new CustomTheme(bgType, bg, navBarConfig, tabbarStyle);
setTabPageTheme(theme)

6.4 在页面中动态切换主题

mine.uvue 页面为例,实现主题切换功能:

vue 复制代码
<template>
	<scroll-view direction="vertical" class="mine-page"
	show-scrollbar = "false"
	enable-back-to-top="true"
	refresher-enabled="true"
	refresher-default-style="none"
	refresher-background="rgba(232, 201, 183, 0.5)"
	:refresher-triggered="data.refreshing2"

	 refresher-max-drag-distance="200px"
		  @refresherpulling="onRefresherpulling2"
		  @refresherrefresh="onRefresherrefresh2"
		  @refresherrestore="onRefresherrestore2"

	 >
	 <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 style="color:#ff4d40">动态设置中心</text>
		</view>
		<view class="tabbar">
			<text class="title-text">tabbar设置</text>
			<button class="tabbar-btn" @click="refresh1">动态tabbar(我的)</button>
			<button class="tabbar-btn" @click="refresh2">动态tabbar(首页、我的)</button>
			<button class="tabbar-btn" @click="refresh3">动态tabbar(算法、我的)</button>
			<button class="tabbar-btn" @click="refresh4">动态tabbar(我的、算法、首页、弹出详情、进入详情)</button>
			<text class="title-text">设置角标</text>
			<input class="input-item" v-model="tabbar" placeholder="请输入tabbar" />
			<input class="input-item" v-model="badge" placeholder="请输入角标" />
			<button class="tabbar-btn" @click="setBadge">确定</button>
			<button class="tabbar-btn" @click="theme">主题1</button>
			<button class="tabbar-btn" @click="theme2">主题2</button>
			<button class="tabbar-btn" @click="theme3">主题3</button>
			<button class="tabbar-btn" @click="clear">clear</button>
			<!-- <button class="tabbar-btn" type="default" @click="refresh">刷新</button> -->
				 	<!-- <button   type="default" @click="cPop">返回</button> -->

		</view>


	</scroll-view>
</template>

<script setup lang="uts">
	import { ref,onMounted,onUnmounted } from 'vue'
	import { TabItem, GLOBAL_COMPONENT_REGISTRY, CustomTheme, TabbarIcon, TabbarStyle, NavBarConfig } from '@/uni_modules/sunrains-tabbar/utssdk/types.uts'
	import { setTabBadge,setTabbarColorHeight,refreshTabbar ,setTabPageTheme,closeTabPop,clearStorage} from '@/uni_modules/sunrains-tabbar/utssdk/noticetab.uts'

 function cPop(){
 	closeTabPop()
 }

   onMounted(() => {
     console.log('【组件挂载====mine===】')
   })

   onUnmounted(() => {
     console.log('【组件销毁====mine===】')
   })


// 用于自动化测试的数据暴露 - 使用 reactive 将所有 ref 状态集中暴露
const data = reactive({
  refreshing2: false,
  pullingDistance2: 0

})

function onRefresherpulling2(e: RefresherEvent) {
  data.pullingDistance2 = e.detail.dy
}
	const refreshing = ref(false)

function onRefresherrefresh2() {
  data.refreshing2 = true
  console.log('触发刷新')
  setTimeout(() => {
    data.refreshing2 = false
    console.log('刷新完成')
  }, 1500)
}

function onRefresherrestore2() {
  data.pullingDistance2 = 0
}

function onRefresherabort2() {
  data.pullingDistance2 = 0
}

	// 上拉触底加载
	const loadMore = () => {
		console.log("滚动到底部", "info")
	}

	function clear() {
		clearStorage("all")
	}

	const bgColor = ref<string>('pink')
	const tabHeight = ref<string>('120')
	const badge = ref<string>('0')
	const ss = ref<any>("");

	// tab 选项配置
	const tabbar = ref<string | null>(null)
	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 setStyle() {
		setTabbarColorHeight(bgColor.value,parseInt(tabHeight.value) )
	}

	function refresh1() {
		console.log("动态tabbar(我的)")
		refreshTabbar([
			new TabItem('mine', "",12, "red", "yellow", "bold", '我的', '/static/tab/main3.png', '/static/tab/main3_active.png',24,24,"tabPage")
		]);
	}
	function refresh2() {
		console.log("动态tabbar(首页、我的)")
		refreshTabbar([
			new TabItem('home', "",12, "red", "yellow", "bold", '首页', '/static/tab/main1.png', '/static/tab/main1_active.png',24,24,"tabPage"),
			new TabItem('mine', "",12, "red", "yellow", "bold", '我的', '/static/tab/main3.png', '/static/tab/main3_active.png',24,24,"tabPage")
		])
	}
	function refresh3() {
		console.log("动态tabbar(算法、我的)")

		refreshTabbar( [
			new TabItem('order', "",12, "red", "yellow", "bold", '算法', '/static/tab/main2.png', '/static/tab/main2_active.png',24,24,"tabPage"),
			new TabItem('mine', "",12, "red", "yellow", "bold", '我的', '/static/tab/main3.png', '/static/tab/main3_active.png',24,24,"tabPage")
		])
	}
	function refresh4() {
		console.log("动态tabbar(我的、算法、首页、弹出详情、进入详情)")

		refreshTabbar([
			new TabItem('mine', "",12, "red", "yellow", "bold", '我的', '/static/tab/main3.png', '/static/tab/main3_active.png',24,24,"tabPage"),
			new TabItem('order', "",12, "red", "yellow", "bold", '算法', '/static/tab/main2.png', '/static/tab/main2_active.png',24,24,"tabPage"),
			new TabItem('home', "",12, "red", "yellow", "bold", '首页', '/static/tab/main1.png',
			 '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=1781283600&t=4feca8b5a1149e3ed0f28ee030f767b4',
			 24,24,"tabPage"
			 ),
			 new TabItem('detail', "",12, "red", "yellow", "bold", '弹出详情', '/static/tab/main1.png',
			  '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=1781283600&t=4feca8b5a1149e3ed0f28ee030f767b4',
			  24,24,"tabPop"
			  ),
			  new TabItem('detail', "/pages/detail/detail",12, "red", "yellow", "bold", '进入详情', '/static/tab/main1.png',
			   '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=1781283600&t=4feca8b5a1149e3ed0f28ee030f767b4',
			   24,24,"page"
			   )
		])
	}


	function theme() {
		//主题背景类型
		let bgType = "IMG"
		//背景 如果是图片传图片路径 颜色则传 具体颜色
		let bg : string = "/static/2.png"
		// let bg:string = "black"
		let navBarConfig : NavBarConfig = new NavBarConfig(true, 34, 'bold', '#FFA500', "rgba(191, 191, 191, 0.5)", "", 90)
		let tabbarIcon = new TabbarIcon("mine",
			"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=1781283600&t=4feca8b5a1149e3ed0f28ee030f767b4",
			"/static/tab/main3_active.png",
			24,24,
			12,
			"green",
			"white",
			"bold"
		)
		let tabbarIcons : Map<string, TabbarIcon> = new Map();
		tabbarIcons.set("mine", tabbarIcon)
		let tabbarStyle : TabbarStyle = new TabbarStyle(120, "rgba(21, 20, 31, 0.8)", tabbarIcons)
		let theme = new CustomTheme(bgType, bg, navBarConfig, tabbarStyle);
		setTabPageTheme(theme)
	}

	function theme2() {
		//主题背景类型
		let bgType  = "IMG"
		//背景 如果是图片传图片路径 颜色则传 具体颜色
		let bg : string = "/static/sm.jpg"
		// let bg:string = "black"
		let navBarConfig : NavBarConfig = new NavBarConfig(false, 34, 'bold', '#0c0c0c', "", "", 90)
		let tabbarIcon = new TabbarIcon("mine",
			"/static/aj.png",
			"/static/aj1.png",
			24,24,
			20,
			"green",
			"red",
			"bold"
		)
		let tabbarIcon1 = new TabbarIcon("home",
			"https://static-mp-4c53170b-e5f8-453b-a634-afcb5cf07d59.next.bspapp.com/img/icon/豪横.gif",
			"https://static-mp-4c53170b-e5f8-453b-a634-afcb5cf07d59.next.bspapp.com/img/icon/豪横.gif",
			50,24,
			16,
			"black",
			"yellow",
			"bold"
		)
		let tabbarIcons : Map<string, TabbarIcon> = new Map();
		tabbarIcons.set("mine", tabbarIcon)
		tabbarIcons.set("home", tabbarIcon1)
		let tabbarStyle : TabbarStyle = new TabbarStyle(120, "rgba(21, 20, 31, 0.4)", tabbarIcons)
		let theme = new CustomTheme(bgType, bg, navBarConfig, tabbarStyle);
		setTabPageTheme(theme)
	}
	function theme3() {
		//主题背景类型
		let bgType  = "IMG"
		//背景 如果是图片传图片路径 颜色则传 具体颜色
		let bg : string = "https://static-mp-4c53170b-e5f8-453b-a634-afcb5cf07d59.next.bspapp.com/img/bizhi/端午1.png"
		// let bg:string = "black"
		let navBarConfig : NavBarConfig = new NavBarConfig(true, 34, 'bold', '#0c0c0c', "", "", 90)
		let tabbarIcon = new TabbarIcon("mine",
			"/static/aj.png",
			"/static/aj1.png",
			24,24,
			16,
			"white",
			"red",
			"bold"
		)
		let tabbarIcon1 = new TabbarIcon("home",
			"/static/sy1.png",
			"/static/sy.png",
			50,24,
			16,
			"white",
			"red",
			"bold"
		)
		let tabbarIcon2 = new TabbarIcon("detail",
			"/static/tab/main2_active.png",
			"/static/tab/main2_active.png",
			24,24,
			16,
			"red",
			"red",
			"bold"
		)
		let tabbarIcons : Map<string, TabbarIcon> = new Map();
		tabbarIcons.set("mine", tabbarIcon)
		tabbarIcons.set("home", tabbarIcon1)
		tabbarIcons.set("detail", tabbarIcon2)
		let tabbarStyle : TabbarStyle = new TabbarStyle(150, "rgba(10, 13, 31, 0.8)", tabbarIcons)
		let theme = new CustomTheme(bgType, bg, navBarConfig, tabbarStyle);
		setTabPageTheme(theme)
	}

	function init() {
		uni.stopPullDownRefresh()
		console.log('stop onPullDownRefresh=====');
	}
	onPullDownRefresh(() => {
		console.log('onPullDownRefresh=====');
		init()

	})

	function refresh() {
		uni.startPullDownRefresh({
			success: () => {
				console.log("1111")
			}
		});
		init()
	}
</script>

<style scoped lang="scss">
	.mine-page {
		height: 100%;
		// border: 12px solid red;
		margin: 5px;
	}

	.page-title {
		margin-bottom: 15px;
		display: flex;
		align-items: center;
		justify-content: center;
		width: 100%;
	}

	.title-text {
		font-size: 18px;
		font-weight: bold;
		color: #333;
	}

	.tabbar {
		// border: 2px solid cyan;
		padding: 15px;
		display: flex;
		flex-direction: column;
	}

	.input-item {
		height: 45px;
		border: 1px solid #ccc;
		border-radius: 6px;
		padding-left: 10px;
		background: #fff;
		margin: 10px;
		padding-left: 20px;
	}

	.picker-item {
		height: 45px;
		border: 1px solid #ccc;
		border-radius: 6px;
		background: #fff;
		margin: 10px;
		display: flex;
		align-items: center;
	}

	.picker-display {
		padding-left: 20px;
		font-size: 16px;
		color: #333;
	}

	.tabbar-btn {
		margin-bottom: 10px;
		border-radius: 8px;
		background: #f5f5f5;
		border: 1px solid #e5e5e5;
		padding: 16px 0;
		font-size: 16px;
	}

	.tabbar-btn:last-child {
		margin-bottom: 0;
	}
</style>

6.5 主题配置注意事项

  1. 颜色格式 :颜色值必须为有效的 CSS 颜色格式(如 #ffffffrgb(255,255,255) 等)
  2. tabbar区域高度单位:高度值为数字类型,单位为 rpx
  3. 动态修改 :通过 uni.$emit('setTheme', new CustomTheme(bgType, bg, navBarConfig, tabbarStyle)) 动态修改的主题会立即生效

7 page页跳转自定义tab页

###使用 pageToTab 方法 跳转到tab页 以 detail.uvue 页面为例,实现主题切换功能:

xml 复制代码
<template>
	
	<view class="detail-root">
	
		<view class="detail-content">
<!-- 
			<view>
				<input v-model="content" placeholder="请输入。。" />
				<text>{{sbase64}}</text>
				<text>{{base64yostr}}</text>
			</view> -->
			<view class = "con">
				<view  class = "com">
					<text>网络请求</text>	
				</view>
				<view>
				
					
					<button class="btn" type="primary" @click="req">访问testvoid</button>
					<button class="btn"  type="primary" @click="reqSm2">访问testSm2</button>
					<button class="btn" type="primary" @click="reqSm4">访问testSm4</button>
					<button class="btn" type="primary" @click="reqSm2Sm4">访问testreqSm2Sm4</button>
				</view>
			</view>
			
			<view class = "con">
				<view class = "com">
					<text>跳转tab页</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/utssdk/noticetab.uts"
	
   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://192.168.1.9:8081"
	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; 
	}
	.con{
		margin:10px 0; 
		padding:10px;
		background-color: #e3eda1;
	}
	.btn{
		margin: 5px;
	}
</style>

8 拓展底部tabbar类型,(切换、弹出、进入)页面

uts 复制代码
	let mine = new TabItem(
		   'mine', //组件或页面唯一标识
			"", //组件或页面路径  当类型为 page 时不可为空,其它传空字符串即可
			12,
			"red",
			"yellow", 
			"bold", 
			'我的', 
			'/static/tab/main3.png',
			'/static/tab/main3_active.png',
			24,//图标宽
			24,//图标高
			"tabPage" //tabbar 类型 tabPage:tab页面  tabPop:弹窗组件  page:普通页面
		)

注: 类型为 tabPop 打开页面 可下滑关闭 或点击虚拟返回按键关闭 或 页面中调用方法 closeTabPop()关闭

方法导入 import { pageToTab} from "@/uni_modules/sunrains-tabbar/utssdk/noticetab.uts"


⚠️ 常见问题

Q1: 为什么小程序端需要单独配置?

A: 微信小程序不支持动态组件渲染,必须静态声明所有可能使用的组件。

Q2: 动态 Tab 刷新失败怎么办?

A: 检查以下几点:

  • 组件是否在 tabbar-config.uts 中正确注册
  • 是否正确使用了 GLOBAL_COMPONENT_REGISTRY.get() 获取组件
  • TabItem 的参数是否完整且类型正确

Q3: 导航栏配置不生效?

A: 确保 setNavbarConfig()setDefaultTabItems() 之前调用,或在应用启动时尽早调用。

Q4: 如何设置数字角标?

A: 使用 uni.$emit('setTabBadge', {"key": "tab_key", "badge": number}) 即可,详见第 4 章。

Q5: 角标设置后不显示怎么办?

A: 检查以下几点:

  • badge 值是否大于 0(0 或负数不显示)
  • tab key 是否正确(必须与 TabItem 的 key 一致)
  • 是否重新赋值了整个数组(直接修改对象属性不会触发响应式)

Q6: 退出登录如何清除 tabbar相关缓存

A: 调用 noticetab.uts里的 clearStorage 方法

go 复制代码
/**
 * 清除tabbar相关缓存
 * all 所有
 * theme 主题
 * tabbarItems 所有tabbar
 * badge 角标
 */
export function clearStorage(type:string){
	switch (type){
		case "theme":
			uni.removeStorageSync("sunrains-tabbar-customtheme")	
			break;
		case "tabbarItems":
			uni.removeStorageSync("sunrains-tabbar-logintabbaritems")
			break;	
		case "badge":
			uni.removeStorageSync("sunrains-tabbar-tabbarbadges")
			break;	
		default:
			uni.removeStorageSync("sunrains-tabbar-customtheme")
			uni.removeStorageSync("sunrains-tabbar-logintabbaritems")
			uni.removeStorageSync("sunrains-tabbar-tabbarbadges")		
	}
	
}

相关推荐
把马铃薯变成土豆2 小时前
前端Stripe跨境支付对接感想
前端·源码
牧艺2 小时前
用 Three.js 实现一个浏览器端 3D 看车的项目
前端·three.js
hunterandroid2 小时前
WorkManager:可靠的后台任务调度
前端
hunterandroid2 小时前
[Android 从零到一] Navigation Component:让页面跳转更清晰
前端
搬砖的码农2 小时前
(05)进程一关对话就没了:聊天记录怎么存、重启怎么恢复
前端·agent·ai编程
Csvn3 小时前
Vue 3 defineModel 翻车实录:多个 v-model 绑定到底怎么写?
前端·vue.js
甲维斯3 小时前
坦克大战测试全翻车了!豆包,DeepSeek,Qwen,GPT,Claude
前端·人工智能·游戏开发
乘风gg4 小时前
还在养虾吗?虾王已诞生:微信龙虾 ClawBot
前端·ai编程·claude
小小小小宇4 小时前
LLM 长期记忆构建
前端