当前位置:   article > 正文

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

uniapp 自定义tabbar

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

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

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

"tabBar": {
    "color": "#ffffff",
	"selectedColor": "#6777FD",
	"custom": true,
	"list": [{},{},{}]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

在需要用到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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

②自定义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 })
    },
  }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

注意:如需实现 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
		})
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
二、具体案例

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": "我的"
		}
	]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

①自定义公共组件

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145

在使用到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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

②自定义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 })
    },
  }
})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

index.json中:

{
  "component": true,
  "usingComponents": {}
}
  • 1
  • 2
  • 3
  • 4

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88

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

onShow() {
	if (typeof this.$mp.page.getTabBar === 'function' && this.$mp.page.getTabBar()) {
		this.$mp.page.getTabBar().setData({
			selected: 1
		})
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

三、疑惑

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

这两者的作用不同:

  • 自定义页面配置项:这些配置项是针对你自定义的页面的,包括页面路径、页面标题、页面使用的窗口配置等。这些配置项用于描述单个页面的属性和行为。
  • app.json 中的 list 配置页面:这些配置项用于描述 TabBar 中的各个页面,包括页面路径、页面标题、页面图标路径等。这些配置项告诉微信客户端哪些页面需要在 TabBar 中显示,并且控制它们在 TabBar 中的位置和样式。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/860498
推荐阅读
相关标签
  

闽ICP备14008679号