在做项目时,经常遇到在现有的框架中无法实现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就行了;
还有一个问题是子组件的跳转可能会有问题,将路径改为绝对路径就行,如果还是不行就在绝对路径前面加上'/' 就没有问题了;
以上就是我遇到的坑,如有问题,欢迎留言!!