【uniapp】开发微信小程序自定义底部tabbar

avatar
作者
筋斗云
阅读量:2

自定义tabBar的性能体验会低于原生tabBar,小程序端非必要不要自定义。但原生tabBar是相对固定的配置方式,可能无法满足所有场景,这就涉及到自定义tabBar。

一、使用流程
1、配置信息

pages.json 中的 tabBar 项指定 custom 字段,同时其余 tabBar 相关配置也补充完整

"tabBar": {     "color": "#ffffff", 	"selectedColor": "#6777FD", 	"custom": true, 	"list": [{},{},{}] } 
2、添加tabBar代码文件

①自定义公共组件

components目录下新建组件页面CustomTabBar,在CustomTabBar.vue中开发自定义组件

在这里插入图片描述

<template> 	<view class="tabBar"></view> </template>  <script> export default { 	props: { 		selected: Number 	}, 	data() { 		return { 			color: "#fff", 			selectedColor: "#6777FD", 			list: [{},{},{}] 		} 	}, 	methods: { 		switchTab(url) { 			uni.switchTab({ 				url 			}) 		} 	} } </script>  <style lang="scss">  </style> 

在需要用到tabBar的页面引入注册并使用组件,通过父子组件通信的方式传参当前是哪个索引页面selected,在子组件通过props接收并使用

<script> 	import CustomTabBar from "@/components/CustomTabBar/CustomTabBar.vue" 	export default { 		components: { 			CustomTabBar 		} 	} </script>  <template> 	<view> 		<custom-tab-bar :selected="1" /> 	</view> </template> 

②自定义tabbar

在这里插入图片描述
根目录创建custom-tab-bar文件夹,里面创建index.js、index.json、index.wxml、index.wxss文件进行开发,而不是vue文件,uniapp编译器会直接拷贝该目录到微信小程序中。

在这里插入图片描述

index.js中:

Component({   /**    * 组件的属性列表    */   properties: {    },    /**    * 组件的初始数据    */   data: {     selected: 0,     color: "#fff",     selectedColor: "#6777FD",     list: [{},{},{}]   },    /**    * 组件的方法列表    */   methods: {     switchTab(e) {       const data = e.currentTarget.dataset       const url = data.path       wx.switchTab({ url })     },   } }) 

注意:如需实现 tab 选中态,要在当前页面下,通过 getTabBar 接口获取组件实例,并调用 setData 更新选中态

onShow() { 	// 原生微信小程序 	 if (typeof this.getTabBar === 'function' && this.getTabBar()) {       this.getTabBar().setData({         selected: 0       })     } 	// vue2 	if (typeof this.$mp.page.getTabBar === 'function' && this.$mp.page.getTabBar()) { 		this.$mp.page.getTabBar().setData({ 			selected: 0 		}) 	} 	// vue3 	if (typeof this.scope.page.getTabBar === 'function' && this.scope.page.getTabBar()) { 		this.scope.page.getTabBar().setData({ 			selected: 0 		}) 	} } 
二、具体案例

pages.json中:

"tabBar": { 	"color": "#ffffff", 	"selectedColor": "#6777FD", 	"custom": true, 	"list": [{ 			"pagePath": "pages/aboutFind/use/use", 			"iconPath": "static/image/icon_find2.png", 			"selectedIconPath": "static/image/icon_find1.png", 			"text": "使用" 		}, 		{ 			"pagePath": "pages/index/index", 			"iconPath": "static/image/icon_go2.png", 			"selectedIconPath": "static/image/icon_go1.png", 			"text": "通行" 		}, 		{ 			"pagePath": "pages/myInfo/myInfo", 			"iconPath": "static/image/icon_set2.png", 			"selectedIconPath": "static/image/icon_set1.png", 			"text": "我的" 		} 	] } 

①自定义公共组件

CustomTabBar.vue中:

<template> 	<view class="tabBar"> 		<view class="cont"> 			<block v-for="(item,index) in list" :key="index" class="cont-item"> 				<view @click="switchTab(item.pagePath)" 					:class="{'search': item.search ? true : false, 'item': !item.search, 'on': selected === index ? true : false, 'off': selected != index ? true : false}"> 					<image :src=" selected===index ? item.selectedIconPath : item.iconPath"> 					</image> 					<view :class="{'txt': true,'selectedColor': selected === index ? true : false}">{{item.text}}</view> 				</view> 			</block> 		</view> 	</view> </template>  <script> export default { 	props: { 		selected: Number 	}, 	data() { 		return { 			color: "#fff", 			selectedColor: "#6777FD", 			list: [{ 					pagePath: "/pages/aboutFind/use/use", 					text: "使用", 					iconPath: "/static/image/icon_find2.png", 					selectedIconPath: "/static/image/icon_find1.png" 				}, 				{ 					pagePath: "/pages/index/index", 					text: "通行", 					iconPath: "/static/image/icon_go2.png", 					selectedIconPath: "/static/image/icon_go1.png", 					search: true 				}, 				{ 					pagePath: "/pages/myInfo/myInfo", 					text: "我的", 					iconPath: "/static/image/icon_set2.png", 					selectedIconPath: "/static/image/icon_set1.png" 				} 			] 		} 	}, 	methods: { 		switchTab(url) { 			uni.switchTab({ 				url 			}) 		} 	} } </script>  <style lang="scss"> .tabBar { 	z-index: 100; 	width: 100%; 	position: fixed; 	bottom: 0; 	font-size: 28rpx; 	background-color: #fff; 	color: #636363; 	border-radius: 50rpx 50rpx 0px 0px; } .cont { 	z-index: 0; 	height: calc(100rpx + env(safe-area-inset-bottom) / 2); 	padding-bottom: 30rpx; 	display: flex; 	justify-content: space-around; 	.item { 		font-size: 24rpx; 		position: relative; 		width: 15%; 		text-align: center; 		padding: 0; 		display: block; 		height: auto; 		line-height: 1; 		margin: 0; 		background-color: inherit; 		overflow: initial; 		justify-content: center; 		align-items: center; 		padding-top: 20rpx; 	} 	.item:first-child { 		right: 45rpx; 	} 	.item:last-child { 		left: 45rpx; 	} 	.item image:first-child { 		width: 43rpx !important; 		height: 43rpx !important; 		margin: auto 	} 	.item image:last-child { 		width: 41rpx !important; 		height: 43rpx !important; 		margin: auto 	} 	.txt { 		margin-top: 20rpx; 	} 	.on { 		position: relative; 	} 	.on:not(:nth-child(2)):before { 		content: ""; 		display: block; 		position: absolute; 		top: 0; 		width: 100%; 		height: 6rpx; 		background-color: #00BCD4; 		border-radius: 120rpx !important; 	} 	.search { 		position: absolute; 		left: 50%; 		transform: translate(-50%, 0); 		top: -50rpx; 		display: flex; 		flex-direction: column; 		justify-content: center; 		align-items: center; 	} 	.search image { 		width: 100rpx !important; 		height: 100rpx !important; 		z-index: 2; 		border-radius: 100%; 	} 	.search .txt { 		margin-top: 26rpx; 	} 	.selectedColor { 		color: #00BCD4; 	} } </style> 

在使用到CustomTabBar.vue组件的三个页面中,如index首页

<script> 	import CustomTabBar from "@/components/CustomTabBar/CustomTabBar.vue" 	export default { 		components: { 			CustomTabBar 		} 	} </script>  <template> 	<view> 	    <!-- 传对应页面在list数组中位置的索引值 --> 		<custom-tab-bar :selected="1" /> 	</view> </template> 

②自定义tabbar

index.js中:

Component({   /**    * 组件的属性列表    */   properties: {    },    /**    * 组件的初始数据    */   data: {     selected: 0,     color: "#fff",     selectedColor: "#6777FD",     list: [       {         pagePath: "/pages/aboutFind/use/use",         text: "使用",         iconPath: "/static/image/icon_find2.png",         selectedIconPath: "/static/image/icon_find1.png"       },       {         pagePath: "/pages/index/index",         text: "通行",         iconPath: "/static/image/icon_go2.png",         selectedIconPath: "/static/image/icon_go1.png",         search: true       },       {         pagePath: "/pages/myInfo/myInfo",         text: "我的",         iconPath: "/static/image/icon_set2.png",         selectedIconPath: "/static/image/icon_set1.png"       }     ]   },    /**    * 组件的方法列表    */   methods: {     switchTab(e) {       const data = e.currentTarget.dataset       const url = data.path       wx.switchTab({ url })     },   } })  

index.json中:

{   "component": true,   "usingComponents": {} } 

index.wxml中:

<view class="tabBar">   <view class="cont">     <block wx:for="{{list}}" wx:key="index" class="cont-item">       <view data-path="{{item.pagePath}}" data-index="{{item.pagePath}}" bindtap="switchTab" class="{{item.search?'search':'item'}} {{selected === index ? 'on' : 'off'}}">         <image src="{{selected === index  ? item.selectedIconPath : item.iconPath}}"></image>         <view class="txt {{selected === index ? 'selectedColor' : ''}}">{{item.text}}</view>       </view>     </block>   </view> </view> 

index.wxss中:

.tabBar {   z-index: 100;   width: 100%;   position: fixed;   bottom: 0;   font-size: 28rpx;   background-color: #fff;   color: #636363;   border-radius: 50rpx 50rpx 0px 0px; } .cont {   z-index: 0;   height: calc(100rpx + env(safe-area-inset-bottom) / 2);   padding-bottom: 30rpx;   display: flex;   justify-content: space-around; } .cont .item {   font-size: 24rpx;   position: relative;   /* flex: 1; */   width: 15%;   text-align: center;   padding: 0;   display: block;   height: auto;   line-height: 1;   margin: 0;   background-color: inherit;   overflow: initial;   justify-content: center;   align-items: center;   padding-top: 20rpx; } .cont .item:first-child {   right: 45rpx; } .cont .item:last-child {   left: 45rpx; } .cont .item image:first-child {   width: 43rpx !important;   height: 43rpx !important;   margin: auto } .cont .item image:last-child {   width: 41rpx !important;   height: 43rpx !important;   margin: auto } .cont .txt {   margin-top: 20rpx; } .cont .on {   position: relative; } .cont .on:not(:nth-child(2)):before {   content: "";   display: block;   position: absolute;   top: 0;   width: 100%;   height: 6rpx;   background-color: #00BCD4;   border-radius:120rpx !important; } .cont .search {   position: absolute;   left: 50%;   transform: translate(-50%,0);   top: -50rpx;   display: flex;   flex-direction: column;   justify-content: center;   align-items: center; } .cont .search image {   width: 100rpx !important;   height: 100rpx !important;   z-index: 2;   border-radius: 100%; } .cont .search .txt {   margin-top: 26rpx; } .cont .selectedColor {   color: #00BCD4; } 

在使用到custom-tab-bar的三个页面中:

onShow() { 	if (typeof this.$mp.page.getTabBar === 'function' && this.$mp.page.getTabBar()) { 		this.$mp.page.getTabBar().setData({ 			selected: 1 		}) 	} } 

在这里插入图片描述

三、疑惑

尽管在自定义页面中已经写了页面的配置项,但在 app.json 中的 list 配置页面仍然是必需的,为什么?

这两者的作用不同:

  • 自定义页面配置项:这些配置项是针对你自定义的页面的,包括页面路径、页面标题、页面使用的窗口配置等。这些配置项用于描述单个页面的属性和行为。
  • app.json 中的 list 配置页面:这些配置项用于描述 TabBar 中的各个页面,包括页面路径、页面标题、页面图标路径等。这些配置项告诉微信客户端哪些页面需要在 TabBar 中显示,并且控制它们在 TabBar 中的位置和样式。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!