uniapp 自定义底部导航栏

1,368 阅读2分钟

封装原因

uniapp提供的tabbar样式无法满足产品需求

注意事项

  • 使用自定义底部导航组件,需要在使用的页面中使用以下代码:uni.hideTabBar();
  • 在pages.json文件中的tabBar对象可以简化配置,如下图

image.png

封装代码

<template>
	<view
		class="tabbar-box"
		:style="{ 'padding-bottom': safeAreaBottomHeight + 'px', 'z-index': zIndex }"
	>
		<view
			class="tabbar-box-item"
			v-for="(item, index) in tabbarList"
			@click="goPage(item)"
			:key="index"
		>
			<image :src="props.type === item.type ? item.activeUrl : item.url"></image>
			<text :class="{ active: props.type === item.type }">{{ item.title }}</text>
		</view>
	</view>
	<!-- 占位 -->
	<view :style="{ height: tabbarHeight + 'px' }"></view>
</template>

<script setup>
	import { ref, onMounted, getCurrentInstance, nextTick } from 'vue';
	import { onLoad } from '@dcloudio/uni-app';
	const { proxy } = getCurrentInstance();

	const props = defineProps({
		type: {
			type: String,
			default: 'home',
		},
		zIndex: {
			type: Number,
			default: 1000,
		},
	});
	const emit = defineEmits(['getTabbarHeight']);

	let tabbarHeight = ref('');
	onMounted(() => {
		getSafeAreaBottomHeight();
		getTabbarHeight();
	});

	const safeAreaBottomHeight = ref(0);
	// 获取安全区域底部高度
	function getSafeAreaBottomHeight() {
		const deviceInfo = uni.getDeviceInfo();
		const windowInfo = uni.getWindowInfo();
		if (deviceInfo.osName == 'ios') {
			safeAreaBottomHeight.value = windowInfo.safeAreaInsets.bottom;
		} else {
			safeAreaBottomHeight.value = windowInfo.safeAreaInsets.bottom
				? windowInfo.safeAreaInsets.bottom
				: 20;
		}
	}
	// 获取 tabbar-box 的高度
	async function getTabbarHeight() {
		await nextTick();
		let query = uni.createSelectorQuery().in(proxy);
		query
			.select('.tabbar-box')
			.boundingClientRect((data) => {
				tabbarHeight.value = data.height;
				emit('getTabbarHeight', tabbarHeight.value);
			})
			.exec();
	}

	let tabbarList = ref([
		{
			title: '首页',
			type: 'home',
			path: '/pages/home/index',
			url: '/static/images/tabbar/home-not-active.png',
			activeUrl: '/static/images/tabbar/home-active.png',
		},
		{
			title: '我的',
			type: 'user',
			path: '/pages/user/index',
			url: '/static/images/tabbar/user-not-active.png',
			activeUrl: '/static/images/tabbar/user-active.png',
		},
	]);

	function goPage(item) {
		if (item.type == props.type) return;
		uni.switchTab({
			url: item.path,
		});
	}
</script>

<style lang="scss" scoped>
	.tabbar-box {
		width: 100%;
		position: fixed;
		bottom: 0;
		left: 0;
		padding: 40rpx 20rpx;
		background: #fff;
		box-shadow: 0rpx -1rpx 21rpx 0rpx rgba(131, 128, 127, 0.1);
		border-radius: 20rpx;
		display: flex;
		justify-content: space-between;
		align-items: center;
		.tabbar-box-item {
			flex: 1;
			display: flex;
			flex-direction: column;
			justify-content: center;
			align-items: center;
			image {
				width: 40rpx;
				height: 40rpx;
				margin-bottom: 10rpx;
			}
			text {
				font-size: 22rpx;
				font-weight: 500;
				color: #999999;
			}
			.active {
				color: #2d99a1;
			}
		}
	}
</style>

页面使用

<myTabbar type="home" @getTabbarHeight=getTabbarHeight></myTabbar>
    onMounted(() => {
    		uni.hideTabBar();
    	});
    function getTabbarHeight(height){
        console.log('tabbarHeight', height);
    }
        

问题解释

Q:为什么使用了自定义tabbar组件还需要保留uniapp提供的tabbar、为什么要在使用组件的页面隐藏tabbar?

A:一开始封装的时候也没有保留原生的tabbar,然后组件中页面跳转的方式使用的就是reLaunch而不是switchTab,但是使用过程中发现每次进行tabbar切换的时候都会导致页面有很明显的切换感觉,和原生的tabbar切换效果相比不够丝滑

Q:其他的跳转方式无法满足吗?

A:其他跳转方式都无法满足要求,navigateTo会增加页面栈、redirectTo和reLaunch一样会导致页面有很明显的切换感觉,所以最后只能使用switchTab方式进行跳转