自定义tabBar的性能体验会低于原生tabBar,小程序端非必要不要自定义。但原生tabBar是相对固定的配置方式,可能无法满足所有场景,这就涉及到自定义tabBar。
一、使用流程
1、配置信息
在
中的 tabBar
项指定 custom
字段,同时其余 tabBar
相关配置也补充完整
"tabBar": {
"color": "#ffffff",
"selectedColor": "#6777FD",
"custom": true,
"list": [{},{},{}]
}
2、添加tabBar代码文件
①自定义公共组件
在components
目录下新建组件页面CustomTabBar
,在中开发自定义组件
<template>
<view class="tabBar"></view>
</template>
<script>
export default {
props: {
selected: Number
},
data() {
return {
color: "#fff",
selectedColor: "#6777FD",
list: [{},{},{}]
}
},
methods: {
switchTab(url) {
({
url
})
}
}
}
</script>
<style lang="scss">
</style>
在需要用到tabBar
的页面引入注册并使用组件,通过父子组件通信
的方式传参当前是哪个索引页面selected
,在子组件通过props
接收并使用
<script>
import CustomTabBar from "@/components/CustomTabBar/"
export default {
components: {
CustomTabBar
}
}
</script>
<template>
<view>
<custom-tab-bar :selected="1" />
</view>
</template>
②自定义tabbar
在根目录
创建custom-tab-bar
文件夹,里面创建、、、
文件进行开发,而不是vue
文件,uniapp编译器会直接拷贝
该目录到微信小程序中。
在中:
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
})
}
}
二、具体案例
在中:
"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": "我的"
}
]
}
①自定义公共组件
在中:
<template>
<view class="tabBar">
<view class="cont">
<block v-for="(item,index) in list" :key="index" class="cont-item">
<view @click="switchTab()"
:class="{'search': ? true : false, 'item': !, 'on': selected === index ? true : false, 'off': selected != index ? true : false}">
<image :src=" selected===index ? : ">
</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>
在使用到组件的三个页面中,如
index首页
:
<script>
import CustomTabBar from "@/components/CustomTabBar/"
export default {
components: {
CustomTabBar
}
}
</script>
<template>
<view>
<!-- 传对应页面在list数组中位置的索引值 -->
<custom-tab-bar :selected="1" />
</view>
</template>
②自定义tabbar
在中:
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 })
},
}
})
在中:
{
"component": true,
"usingComponents": {}
}
在中:
<view class="tabBar">
<view class="cont">
<block wx:for="{{list}}" wx:key="index" class="cont-item">
<view data-path="{{}}" data-index="{{}}" bindtap="switchTab" class="{{?'search':'item'}} {{selected === index ? 'on' : 'off'}}">
<image src="{{selected === index ? : }}"></image>
<view class="txt {{selected === index ? 'selectedColor' : ''}}">{{}}</view>
</view>
</block>
</view>
</view>
在中:
.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
})
}
}
三、疑惑
尽管在自定义页面中已经写了页面的配置项,但在 中的 list 配置页面仍然是必需的,为什么?
这两者的作用不同:
- 自定义页面配置项:这些配置项是针对你自定义的页面的,包括页面路径、页面标题、页面使用的窗口配置等。这些配置项用于描述单个页面的属性和行为。
- 中的 list 配置页面:这些配置项用于描述 TabBar 中的各个页面,包括页面路径、页面标题、页面图标路径等。这些配置项告诉微信客户端哪些页面需要在 TabBar 中显示,并且控制它们在 TabBar 中的位置和样式。