uniapp 、vue2/3自定义底部 tabbar 导航栏凹凸透明显示,高级效果。(兼容h5、微信小程序、app)

目录

1.项目介绍

2.不同端的效果展示图

2.1无底部安全区域:

2.2有底部安全区域:

3. 代码编写

3.1 html 代码部分:

3.2 html 核心代码:

3.3 css 代码部分:

3.4 css 核心代码:

3.5 vue2 代码编写:

3.6 vue3 代码编写:

3.7 vue2/3 核心代码:

3.8 Tabbar 组件的使用:

4. vue2 完整代码

5. vue3 完整代码


1.项目介绍

项目描述:uniapp 使用 vue2/3,自定义封装 tabbar,底部凹凸透明显示。兼容h5、微信小程序、app等。html 和 css 部分代码一样,只有 js 功能代码,分别使用 vue2 和 vue3 的写法。

兼容性:h5、微信小程序、app端兼容,其他端没有测试过,应该也兼容的。

技术栈:uniapp + vue2 /3。

2.不同端的效果展示图

2.1无底部安全区域:

h5端,底部是没有安全区域的,效果图如下:

h5端,无底部安全区域效果图

2.2有底部安全区域:

微信小程序端app端中,苹果手机底部可能会有安全区域,效果图如下

微信小程序和app中,底部安全区域显示效果图

3. 代码编写

3.1 html 代码部分:

<template>
	<view class="tabbar" :style="`--repeat: ${tabbar.length}`">
		<view class="tabbar-nav">
			<view class="tabbar-nav-a" v-for="(item, index) in tabbar" :key="index"
				:class="pageIndex == index ? 'after' : ''" @tap="tapTabbar(item, index)">
				<view class="after-icon" v-if="pageIndex == index">
					<uni-icons :type="item.selectedIconPath" size="60rpx" color="#fff"></uni-icons>
				</view>
				<uni-icons :type="item.iconPath" size="48rpx" v-else></uni-icons>
				<text class="text">{{ item.text }}</text>
			</view>
		</view>
		<view class="safeZone" :style="{ 'height': safeAreaInsetsBottom }"></view>
	</view>
	<view :style="{ 'height': tabbarHeight }"></view>
</template>

3.2 html 核心代码:

:style="`--repeat: ${tabbar.length}`" tabbar的数量,根据数组的长度改变。

:style="{ 'height': safeAreaInsetsBottom }" :底部安全区域的高度。

:style="{ 'height': tabbarHeight }":tabbar导航栏的高度,防止内容被遮挡。


3.3 css 代码部分:

<style lang="scss" scoped>
.tabbar {
	--width: 100rpx;
	--height: 100rpx;
	--size: 60rpx;
	--repeat: 4;
	--color: #FC536E;
	--radius: 20rpx;
	--rgba: rgba(255, 255, 255, 0.95);
	position: fixed;
	width: 100%;
	bottom: 0;
	z-index: 999;

	.tabbar-nav {
		display: grid;
		grid-template-columns: repeat(var(--repeat), 1fr);

		.tabbar-nav-a {
			display: flex;
			flex-direction: column;
			align-items: center;
			justify-content: flex-end;
			padding: 4rpx 0;
			position: relative;
			height: var(--height);
			background-color: var(--rgba);
			box-sizing: border-box;
			filter: drop-shadow(2rpx -2rpx 2rpx rgba(0, 0, 0, 0.1));
			font-size: 24rpx;

			&:nth-child(1) {
				border-top-left-radius: var(--radius);
			}

			&:nth-last-child(1) {
				border-top-right-radius: var(--radius);
			}
		}

		.after {
			background: radial-gradient(circle at center top, transparent var(--size), var(--rgba) 0)center top;

			.after-icon {
				width: var(--width);
				height: var(--height);
				background-color: var(--color);
				border-radius: 50%;
				position: absolute;
				left: 50%;
				top: 0;
				transform: translate(-50%, -50%);
				display: flex;
				align-items: center;
				justify-content: center;
			}

			text {
				color: var(--color);
			}
		}
	}

	.safeZone {
		background-color: var(--rgba);
	}
}
</style>

3.4 css 核心代码:

background: radial-gradient(circle at center top, transparent var(--size), var(--rgba) 0)center top;凹凸透明显示,最主要就是靠这行样式代码。

--repeat: 4;:控制 tabbar 的数量


3.5 vue2 代码编写:

<script>
export default {
	name: "Tabbar",
	props: {
		pageIndex: {
			type: Number,
			default: 0,
		}
	},
	data() {
		return {
			tabbarHeight: '',
			safeAreaInsetsBottom: '',
			tabbar: [{
				iconPath: "heart",
				selectedIconPath: "heart-filled",
				text: "爱吧",
				pagePath: "/pages/index/index"
			},
			{
				iconPath: "wallet",
				selectedIconPath: "wallet-filled",
				text: "记账",
				pagePath: "/pages/bookkeeping/bookkeeping"

			},
			{
				iconPath: "chat",
				selectedIconPath: "chat-filled",
				text: "社区",
				pagePath: "/pages/community/community"

			},
			{
				iconPath: "person",
				selectedIconPath: "person-filled",
				text: "我",
				pagePath: "/pages/my/my"
			}]
		}
	},
	created() {
		uni.hideTabBar({ animation: true })
		let res = uni.getWindowInfo().safeAreaInsets.bottom + 50
		this.safeAreaInsetsBottom = res + "rpx";
		this.tabbarHeight = res * 2 + "rpx"
	},
	methods: {
		tapTabbar(val, index) {
			uni.switchTab({
				url: val.pagePath
			})
		}
	}

}
</script>

3.6 vue3 代码编写:

<script setup>
	defineOptions({
		name: "Tabbar"
	});
	const tabbarHeight = ref('')
	const safeAreaInsetsBottom = ref(0)
	
	const props = defineProps({
		pageIndex: {
			type: Number,
			default: 0
		}
	});
	const tabbar = reactive([{
			iconPath: "heart",
			selectedIconPath: "heart-filled",
			text: "爱吧",
			pagePath: "/pages/index/index"
		},
		{
			iconPath: "wallet",
			selectedIconPath: "wallet-filled",
			text: "记账",
			pagePath: "/pages/bookkeeping/bookkeeping"

		},
		{
			iconPath: "chat",
			selectedIconPath: "chat-filled",
			text: "社区",
			pagePath: "/pages/community/community"

		},
		{
			iconPath: "person",
			selectedIconPath: "person-filled",
			text: "我",
			pagePath: "/pages/my/my"
		}

	])
	onMounted(() => {
		uni.hideTabBar({ animation: true })
		let res = uni.getWindowInfo().safeAreaInsets.bottom
		safeAreaInsetsBottom.value = res * 2 + "rpx";
		tabbarHeight.value = res + 50 * 2 + "rpx";
	});
	const tapTabbar = (val, index) => {
		uni.switchTab({
			url: val.pagePath
		})
	}
</script>

3.7 vue2/3 核心代码:

uni.hideTabBar({ animation: true })  :隐藏默认的 tabBar 。

let res = uni.getWindowInfo().safeAreaInsets.bottom :获取底部安全区域的高度,返回px单位。

this.safeAreaInsetsBottom = res * 2 + "rpx":将高度 px单位 转为 rpx单位。

this.tabbarHeight = res + 50 * 2 + "rpx" :(底部安全区域高度 + 导航栏自身高度)转 rpx单位。


3.8 Tabbar 组件的使用:

<Tabbar :pageIndex="0"></Tabbar>

:pageIndex="0":用于控制激活状态,高亮显示。


4. vue2 完整代码

<template>
	<view class="tabbar" :style="`--repeat: ${tabbar.length}`">
		<view class="tabbar-nav">
			<view class="tabbar-nav-a" v-for="(item, index) in tabbar" :key="index"
				:class="pageIndex == index ? 'after' : ''" 
				@tap="tapTabbar(item, index)">
				<view class="after-icon" v-if="pageIndex == index">
					<uni-icons size="60rpx" color="#fff" 
					:type="item.selectedIconPath" ></uni-icons>
				</view>
				<uni-icons :type="item.iconPath" size="48rpx" v-else></uni-icons>
				<text class="text">{{ item.text }}</text>
			</view>
		</view>
		<view class="safeZone" :style="{ 'height': safeAreaInsetsBottom }"></view>
	</view>
	<view :style="{ 'height': tabbarHeight }"></view>
</template>
<script>
export default {
	name: "Tabbar",
	props: {
		pageIndex: {
			type: Number,
			default: 0,
		}
	},
	data() {
		return {
			tabbarHeight: '',
			safeAreaInsetsBottom: '',
			tabbar: [{
				iconPath: "heart",
				selectedIconPath: "heart-filled",
				text: "爱吧",
				pagePath: "/pages/index/index"
			},
			{
				iconPath: "wallet",
				selectedIconPath: "wallet-filled",
				text: "记账",
				pagePath: "/pages/bookkeeping/bookkeeping"

			},
			{
				iconPath: "chat",
				selectedIconPath: "chat-filled",
				text: "社区",
				pagePath: "/pages/community/community"

			},
			{
				iconPath: "person",
				selectedIconPath: "person-filled",
				text: "我",
				pagePath: "/pages/my/my"
			}]
		}
	},
	created() {
		uni.hideTabBar({ animation: true })
		let res = uni.getWindowInfo().safeAreaInsets.bottom
		this.safeAreaInsetsBottom = res * 2 + "rpx";
		this.tabbarHeight = res + 50 * 2 + "rpx"
	},
	methods: {
		tapTabbar(val, index) {
			uni.switchTab({
				url: val.pagePath
			})
		}
	}

}
</script>
<style lang="scss" scoped>
.tabbar {
	--width: 100rpx;
	--height: 100rpx;
	--size: 60rpx;
	--repeat: 4;
	--color: #FC536E;
	--radius: 20rpx;
	--rgba: rgba(255, 255, 255, 0.95);
	position: fixed;
	width: 100%;
	bottom: 0;
	z-index: 999;

	.tabbar-nav {
		display: grid;
		grid-template-columns: repeat(var(--repeat), 1fr);

		.tabbar-nav-a {
			display: flex;
			flex-direction: column;
			align-items: center;
			justify-content: flex-end;
			padding: 4rpx 0;
			position: relative;
			height: var(--height);
			background-color: var(--rgba);
			box-sizing: border-box;
			filter: drop-shadow(2rpx -2rpx 2rpx rgba(0, 0, 0, 0.1));
			font-size: 24rpx;

			&:nth-child(1) {
				border-top-left-radius: var(--radius);
			}

			&:nth-last-child(1) {
				border-top-right-radius: var(--radius);
			}
		}

		.after {
			background: radial-gradient(circle at center top, 
			transparent var(--size), var(--rgba) 0)center top;

			.after-icon {
				width: var(--width);
				height: var(--height);
				background-color: var(--color);
				border-radius: 50%;
				position: absolute;
				left: 50%;
				top: 0;
				transform: translate(-50%, -50%);
				display: flex;
				align-items: center;
				justify-content: center;
			}

			text {
				color: var(--color);
			}
		}
	}

	.safeZone {
		background-color: var(--rgba);
	}
}
</style>

5. vue3 完整代码

<template>
	<view class="tabbar" :style="`--repeat: ${tabbar.length}`">
		<view class="tabbar-nav">
			<view class="tabbar-nav-a" v-for="(item, index) in tabbar" :key="index"
				:class="pageIndex == index ? 'after' : ''" 
				@tap="tapTabbar(item, index)">
				<view class="after-icon" v-if="pageIndex == index">
					<uni-icons size="60rpx" color="#fff" 
					:type="item.selectedIconPath">	
					</uni-icons>
				</view>
				<uni-icons :type="item.iconPath" size="48rpx" v-else></uni-icons>
				<text class="text">{{ item.text }}</text>
			</view>
		</view>
		<view class="safeZone" :style="{ 'height': safeAreaInsetsBottom }"></view>
	</view>
	<view :style="{ 'height': tabbarHeight }"></view>
</template>
<script setup>
	defineOptions({
		name: "Tabbar"
	});
	const tabbarHeight = ref('')
	const safeAreaInsetsBottom = ref(0)
	
	const props = defineProps({
		pageIndex: {
			type: Number,
			default: 0
		}
	});
	const tabbar = reactive([{
			iconPath: "heart",
			selectedIconPath: "heart-filled",
			text: "爱吧",
			pagePath: "/pages/index/index"
		},
		{
			iconPath: "wallet",
			selectedIconPath: "wallet-filled",
			text: "记账",
			pagePath: "/pages/bookkeeping/bookkeeping"

		},
		{
			iconPath: "chat",
			selectedIconPath: "chat-filled",
			text: "社区",
			pagePath: "/pages/community/community"

		},
		{
			iconPath: "person",
			selectedIconPath: "person-filled",
			text: "我",
			pagePath: "/pages/my/my"
		}

	])
	onMounted(() => {
		uni.hideTabBar({ animation: true })
		let res = uni.getWindowInfo().safeAreaInsets.bottom
		safeAreaInsetsBottom.value = res * 2 + "rpx";
		tabbarHeight.value = res + 50 * 2 + "rpx";
	});
	const tapTabbar = (val, index) => {
		uni.switchTab({
			url: val.pagePath
		})
	}
</script>
<style lang="scss" scoped>
.tabbar {
	--width: 100rpx;
	--height: 100rpx;
	--size: 60rpx;
	--repeat: 4;
	--color: #FC536E;
	--radius: 20rpx;
	--rgba: rgba(255, 255, 255, 0.95);
	position: fixed;
	width: 100%;
	bottom: 0;
	z-index: 999;

	.tabbar-nav {
		display: grid;
		grid-template-columns: repeat(var(--repeat), 1fr);

		.tabbar-nav-a {
			display: flex;
			flex-direction: column;
			align-items: center;
			justify-content: flex-end;
			padding: 4rpx 0;
			position: relative;
			height: var(--height);
			background-color: var(--rgba);
			box-sizing: border-box;
			filter: drop-shadow(2rpx -2rpx 2rpx rgba(0, 0, 0, 0.1));
			font-size: 24rpx;

			&:nth-child(1) {
				border-top-left-radius: var(--radius);
			}

			&:nth-last-child(1) {
				border-top-right-radius: var(--radius);
			}
		}

		.after {
			background: radial-gradient(circle at center top, 
			transparent var(--size), 
			var(--rgba) 0)center top;

			.after-icon {
				width: var(--width);
				height: var(--height);
				background-color: var(--color);
				border-radius: 50%;
				position: absolute;
				left: 50%;
				top: 0;
				transform: translate(-50%, -50%);
				display: flex;
				align-items: center;
				justify-content: center;
			}

			text {
				color: var(--color);
			}
		}
	}

	.safeZone {
		background-color: var(--rgba);
	}
}
</style>

  • 34
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
UniApp 是一个使用 Vue.js 开发跨平台应用的前端框架,它支持将代码一次编写,即可发布到多个平台,包括微信小程序。在 UniApp 中,自定义底部 tabbar 非常简单,只需要在 pages.json 中指定 tabBar 配置,然后在页面中使用自己的自定义 tabbar 组件即可。 以下是自定义底部 tabbar 的步骤: 1. 在 pages.json 文件中设置 tabBar 配置,如下所示: ```javascript { "tabBar": { "custom": true, // 使用自定义tabBar "color": "#7A7E83", "selectedColor": "#3cc51f", "backgroundColor": "#ffffff", "borderStyle": "white", "list": [ { "pagePath": "pages/index/index", "text": "首页", "iconPath": "/static/tabbar/home.png", "selectedIconPath": "/static/tabbar/home-active.png" }, { "pagePath": "pages/user/user", "text": "我的", "iconPath": "/static/tabbar/user.png", "selectedIconPath": "/static/tabbar/user-active.png" } ] } } ``` 2. 在页面中引入自己的自定义 tabbar 组件,并使用该组件替换默认的 tabBar,如下所示: ```javascript <template> <view> <router-view /> <my-tab-bar :list="list" :active.sync="active" /> </view> </template> <script> import MyTabBar from '@/components/MyTabBar.vue' export default { components: { MyTabBar }, data () { return { active: 0, list: [ { text: '首页', icon: '/static/tabbar/home.png', selectedIcon: '/static/tabbar/home-active.png', path: '/pages/index/index' }, { text: '我的', icon: '/static/tabbar/user.png', selectedIcon: '/static/tabbar/user-active.png', path: '/pages/user/user' } ] } } } </script> ``` 以上是自定义底部 tabbar 的简单介绍,如果您需要更详细的内容,请查看 UniApp 的官方文档。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值