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")		
	}
	
}

相关推荐
To_OC1 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
vipbic1 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy1 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志2 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble3 小时前
c端系统,其实更像一个信息展示平台
前端
李姆斯4 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜4 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司5 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能
江华森5 小时前
Web 开发基础:HTTP 与 REST
前端·网络协议·http
IT_陈寒6 小时前
Redis的KEYS命令把我搞崩溃了,改用SCAN才活过来
前端·人工智能·后端