uniapp 自定义底部导航栏

33 篇文章 6 订阅
8 篇文章 0 订阅

在做项目时,经常遇到在现有的框架中无法实现UI图上的样式,比如说将底部导航栏的字体在选中状态下变为渐变色,在浏览器上可以直接修改css样式,但是运行到真机时才发现根本不生效,查阅官方文档才发现app端的根本不支持这些属性更改

下面是我在项目中做底部导航栏的过程

1.首先是用的官方的底部导航栏,具体可以看我的这篇文档https://blog.csdn.net/weixin_50606255/article/details/116270949

在用这个底部导航栏时,就无法更改字体颜色为渐变色(app端)

 2. 要实现UI设计图的效果,就要自定义底部导航栏了,这里代码可以直接复制使用;

<template>
	<view class="uni-tabbar">
		<view class="uni-tabbar__item" v-for="(item,index) in tabbar" :key="index" @tap="changeTab(item)">
			<!-- 上面使用的是字体图标,解决切换页面的时候图标会闪的效果,毕竟每切换一个页面都会闪一下不太好看,可以切换使用下面的图片方式 -->
			<view v-if="true" class="uni-tabbar__bd">
				<view class="uni-tabbar__icon">
					<img v-if="item.pagePath == pagePath" class="uni-w-42 uni-h-42" :src="item.selectedIconPath" />
					<img v-else class="uni-w-42 uni-h-42" :src="item.iconPath" />
				</view>
			</view>
			<view class="uni-tabbar__label">
				{{item.text}}
			</view>
		</view>
	</view>
</template>
<script>
	export default {
		props: {
			pagePath: null
		},
		data() {
			return {
				page: 'contact',
				showPage: false,
				containerHeight: 400,
				tabbar: [{
						"pagePath": "/pages/home/home",
						"iconPath": "static/img/tob_front_icon_normal.png", //未选中tab图标路径
						"selectedIconPath": "static/img/tob_front_icon_selected.png", //选中tab图标路径
						"text": "首页",
					},
					{
						"pagePath": "/pages/monitor/monitor", //页面路径
						"text": "监控", //tab字体显示
						"iconPath": "static/img/tob_News_icon_normal.png", //未选中tab图标路径
						"selectedIconPath": "static/img/tob_News_icon_selected.png" //选中tab图标路径
					}, {
						"pagePath": "/pages/fund/fund",
						"text": "理财",
						"iconPath": "static/img/tob_wealth_icon_normal.png",
						"selectedIconPath": "static/img/tob_wealth_icon_selected.png"
					},
					{
						"pagePath": "/pages/strategy/strategy", //页面路径
						"text": "推广", //tab字体显示
						"iconPath": "static/img/tob_News_icon_normal.png", //未选中tab图标路径
						"selectedIconPath": "static/img/tob_News_icon_selected.png" //选中tab图标路径
					},
					{
						"pagePath": "/pages/my/my",
						"iconPath": "static/img/tob_my_icon_normal.png", //未选中tab图标路径
						"selectedIconPath": "static/img/tob_my_icon_selected.png", //选中tab图标路径
						"text": "我的",
					}
				]
			};
		},
		onLoad() {
			console.log(this.pagePath)
		},
		methods: {
			changeTab(item) {
				let currentPage = item.pagePath;
				uni.showLoading({
					title: '正在加载...'
				})
				uni.redirectTo({
					url: currentPage,
					success: (e) => {
						uni.hideLoading();
					},
					fail: (e) => {
					}
				})
			},
		}
	}
</script>
<style lang="scss" scoped>
	.uni-tabbar {
		position: fixed;
		bottom: 0;
		z-index: 999;
		width: 100%;
		height: 6%;
		display: flex;
		justify-content: space-around;
		
		padding: 7rpx 0;
		box-sizing: border-box;
		background-color: #fff;
		box-shadow: 0px 10px 20px 0px rgba(75, 51, 100, 0.05);

		.uni-tabbar__item {
			display: flex;
			flex-direction: column;
			.uni-tabbar__bd { // tabBar单项
				.uni-tabbar__icon { // tabBar图标
					width: 54rpx;
					height: 83rpx;
					img {
						width: 100%;
						height: 100%;
					}
				}
			}

			.uni-tabbar__label { // tabBar文字
				font-size: 22rpx;
				font-family: $PF-SC-Rfamily;
				font-weight: 400;
				color: #D8DCE7;
				text-align: center;
				&.active {
					background-image: linear-gradient(to right top, #1CFDF1, #B330FF);
					font-size: 22rpx;
					-webkit-background-clip: text;
					-moz-background-clip: text;
					background-clip: text;
					box-decoration-break: clone;
					-webkit-box-decoration-break: clone;
					-moz-box-decoration-break: clone;
					color: transparent;
					position: relative;
				}
			}
		}

		// .uni-tabbar__icon {
		// 	height: 42upx;
		// 	line-height: 42upx;
		// 	text-align: center;
		// }

		.icon {
			display: inline-block;
		}

		// .uni-tabbar__label {
		// 	line-height: 24upx;
		// 	font-size: 24upx;
		// 	color: #999;

		// 	&.active {
		// 		color: #1ca6ec;
		// 	}
		// }
	}
</style>

在main.js里面全局注入

再在你需要的页面引入

 这样可以得到一个这样的导航栏了

 这样写是实现了渐变色导航栏,但是有一个bug,就是在切换页面时,底部导航栏会重新加载,看起来没有那么丝滑,因为这是的写法是,匹配每个页面组件传过来的值,符合条件就进行跳转,相当于跳转到新的页面。

3.为了改变这个显示上的bug,我又换了一种写法,模仿选项卡的样式

<template>
	<view>
		<view class="content">
			<homePage v-if="currentPage == 0"/>
			<monitorPage v-if="currentPage == 1"/>
			<fundPage v-if="currentPage == 2"/>
			<stragePage v-if="currentPage == 3"/>
			<myPage v-if="currentPage == 4" />
		</view>
		<view class="tabbar" :style="{'padding-bottom': paddingBottomHeight + 'rpx'}">
		<!-- <view class="tabbar"> -->
			<view class="tabbar-item" v-for="(item, index) in list" :key="index" @click="tabbarChange(index)">
				<image class="item-img" :src="item.icon_a" v-if="currentPage == index"></image>
				<image class="item-img" :src="item.icon" v-else></image>
				<view class="item-name" :class="{'tabbarActive': currentPage == index}" v-if="item.text">{{item.text}}
				</view>
			</view>
		</view>
	</view>
</template>
<script>
	import homePage from "../pages/home/home.vue";
	import monitorPage from "../pages/monitor/monitor.vue";
	import fundPage from "../pages/fund/fund.vue";
	import stragePage from "../pages/strategy/strategy.vue";
	import myPage from "../pages/my/my.vue";
	export default {
		components: {
			homePage,
			monitorPage,
			fundPage,
			stragePage,
			myPage
		},
		data() {
			return {
				currentPage: 0,
				paddingBottomHeight: 0, //苹果X以上手机底部适配高度
				list: [{
					text: '首页',
					icon: "/static/img/tob_front_icon_normal.png", //未选中图标
					icon_a: "/static/img/tob_front_icon_selected.png", //选中图片
					path: "/pages/home/home", //页面路径
				}, {
					text: '实训',
					icon: "/static/img/tob_Facts_icon_normal.png", //未选中图标
					icon_a: "/static/img/tob_Facts_icon_selected.png", //选中图片
					path: "/pages/monitor/monitor", //页面路径
				}, {
					text: '理财',
					icon: "/static/img/tob_wealth_icon_normal.png",
					icon_a: "/static/img/tob_wealth_icon_selected.png",
					path: "/pages/fund/fund",
				}, {
					text: '推广',
					icon: "/static/img/tob_Promote_icon_normal.png",
					icon_a: "/static/img/tob_Promote_icon_selected.png",
					path: "/pages/strategy/strategy",
				}, {
					text: '我的',
					icon: "/static/img/tob_my_icon_normal.png",
					icon_a: "/static/img/tob_my_icon_selected.png",
					path: "/pages/my/my",
				}, ]
			};
		},
		created() {
		    let that = this;
		    uni.getSystemInfo({
		        success: function (res) {
		            let model = ['X', 'XR', 'XS', '11', '12', '13', '14', '15'];
		            model.forEach(item => {
		                //适配iphoneX以上的底部,给tabbar一定高度的padding-bottom
		                if(res.model.indexOf(item) != -1 && res.model.indexOf('iPhone') != -1) {
		                    that.paddingBottomHeight = 40;
		                }
		            })
		        }
		    });
		},
		watch: {

		},
		methods: {
			tabbarChange(index) {
				this.currentPage = index;
			}
		}
	};
</script>

 

<style lang="scss" scoped>
	.content {
		width: 100%;
		height: 94%;
	}

	.tabbar {
		position: fixed;
		bottom: 0;
		left: 0;
		right: 0;
		display: flex;
		justify-content: space-around;
		align-items: center;
		width: 100%;
		height: 6%;
		background-color: #ffffff;

		.tabbar-item {
			display: flex;
			flex-direction: column;
			align-items: center;
			justify-content: center;
			width: 56rpx;
			height: 85%;

			.item-img {
				width: 54rpx;
				height: 54rpx;
			}

			.item-name {
				text-align: center;
				font-size: 22rpx;
				font-weight: 400;
				font-family: $PF-SC-Rfamily;
				color: #D8DCE7;
			}

			.tabbarActive {
				background-image: linear-gradient(to right top, #1CFDF1, #B330FF);
				font-size: 22rpx;
				-webkit-background-clip: text;
				-moz-background-clip: text;
				background-clip: text;
				box-decoration-break: clone;
				-webkit-box-decoration-break: clone;
				-moz-box-decoration-break: clone;
				color: transparent;
				position: relative;
				animation: mymove 2s infinite;
			}

			@keyframes mymove {
				0% {
					transform: scale(1);
					/*开始为原始大小*/
				}

				25% {
					transform: scale(1.2);
					/*放大1.1倍*/
				}

				50% {
					transform: scale(1);
				}

				75% {
					transform: scale(1.2);
				}

			}
		}
	}
</style>

这样就能完美实现我想要的效果了,并且还给底部选项卡添加了动画,以上代码都可以直接复制使用,亲测有效(app端和h5端);

但是这样写之后可以子组件的无法请求数据,是因为这样写改变了子组件的生命周期,将onLoad改成vue中的mounted就行了;

还有一个问题是子组件的跳转可能会有问题,将路径改为绝对路径就行,如果还是不行就在绝对路径前面加上'/' 就没有问题了;

以上就是我遇到的坑,如有问题,欢迎留言!!

  • 15
    点赞
  • 86
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
UniApp中,你可以使用自定义组件来实现底部导航栏。下面是一个简单的示例: 1. 创建一个自定义底部导航栏的组件,例如 "CustomTabBar.vue"。 ```html <template> <div class="custom-tab-bar"> <div v-for="(item, index) in tabList" :key="index" class="tab-item" :class="{ active: activeIndex === index }" @click="handleTabClick(index)" > <img :src="item.icon" class="tab-icon" /> <span class="tab-title">{{ item.title }}</span> </div> </div> </template> <script> export default { props: { tabList: { type: Array, required: true, }, activeIndex: { type: Number, required: true, }, }, methods: { handleTabClick(index) { // 触发底部导航栏切换事件,你可以在这里进行路由跳转或其他操作 this.$emit('tabChange', index); }, }, }; </script> <style scoped> .custom-tab-bar { display: flex; justify-content: space-between; padding: 10px; background-color: #f5f5f5; } .tab-item { display: flex; flex-direction: column; align-items: center; cursor: pointer; } .tab-icon { width: 24px; height: 24px; } .tab-title { margin-top: 5px; } </style> ``` 2. 在需要使用底部导航栏的页面中引入自定义组件,并传入相应的参数。 ```html <template> <div> <!-- 页面内容 --> <!-- ... --> <!-- 底部导航栏 --> <custom-tab-bar :tabList="tabList" :activeIndex="activeIndex" @tabChange="handleTabChange" /> </div> </template> <script> import CustomTabBar from '@/components/CustomTabBar.vue'; export default { components: { CustomTabBar, }, data() { return { tabList: [ { title: '首页', icon: 'path/to/home.png' }, { title: '分类', icon: 'path/to/category.png' }, { title: '我的', icon: 'path/to/my.png' }, ], activeIndex: 0, }; }, methods: { handleTabChange(index) { // 处理底部导航栏切换事件 this.activeIndex = index; }, }, }; </script> ``` 在上面的示例中,你可以根据自己的需求修改底部导航栏的样式和功能。注意,这里的路由跳转需要你根据自己的项目配置进行处理。 希望对你有所帮助!如果还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值