uniapp 自定义底部导航栏
在做项目时,经常遇到在现有的框架中无法实现UI图上的样式,比如说将底部导航栏的字体在选中状态下变为渐变色,在浏览器上可以直接修改css样式,但是运行到真机时才发现根本不生效,查阅官方文档才发现app端的根本不支持这些属性更改下面是我在项目中做底部导航栏的过程1.首先是用的官方的底部导航栏,具体可以看我的这篇文档https://blog.csdn.net/weixin_50606255/articl
在做项目时,经常遇到在现有的框架中无法实现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就行了;
还有一个问题是子组件的跳转可能会有问题,将路径改为绝对路径就行,如果还是不行就在绝对路径前面加上'/' 就没有问题了;
以上就是我遇到的坑,如有问题,欢迎留言!!
更多推荐
所有评论(0)