uniapp 实现自定义底部导航栏(中间凸起、有角标)

615 阅读2分钟

代码tabbar.vue

<template>
  <view class="tabbar-container">
    <view
      v-for="(item, index) in tabbarList"
      :key="item.id"
      class="tabbar-item"
      :class="[item.centerItem ? 'center-item' : '']"
      @click="changeItem(item)"
    >
      <view class="item-top">
        <view class="bg-grey">
        	<image :src="currentPage === item.id ? item.selectIcon : item.icon" />
					<uni-badge v-if="item.badgeNum > 0" class="item-uni-badge" :text="item.badgeNum" type="error"></uni-badge>
        </view>
      </view>
      <view class="item-bottom" :class="[currentItem === item.id ? 'item-active' : '']">
        <text>{{ item.text }}</text>
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref, onMounted, computed } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { onLoad, onUnload, onHide } from '@dcloudio/uni-app';
import { useStore } from "vuex";

// 获取路由实例
const router = useRouter();
const route = useRoute();
const store = useStore();

// 定义属性
const props = defineProps({
  currentPage: {
    type: Number,
    default: 0
  }
});
const selectCartNum = uni.getStorageSync('selectCartNum');
const selectCount = ref(0)
// 状态定义
const currentItem = ref(props.currentPage);

const tabbarList = ref([
  {
    id: 0,
    path: '/pages/...', // 页面地址
    icon: '/static/...', // 图标地址/链接
    selectIcon: '/static/...', // 选中后的图标地址/链接
    text: '首页', //页面名称
    centerItem: false,
    badgeNum: 0
  },
  {
    id: 1,
    path: '/pages/...',
    icon: '/static/...',
    selectIcon: '/static/...',
    text: '分类',
    centerItem: false,
    badgeNum: computed(() => store.state.cartNum)
  },
  ... // 写自己的导航内容
]);

// 生命周期钩子
onLoad(() => {
	console.log('onLoad');
  currentItem.value = props.currentPage;
  uni.hideTabBar();
	selectCount.value = selectCartNum ? selectCartNum : 0
	console.log('selectCount',computed(() => store.state.cartNum));
});

// 方法定义
const changeItem = (item) => {
	console.log('item.id;',item.id);
  currentItem.value = item.id;
  uni.switchTab({
    url: item.path
  });
};
</script>

<style>
view {
		padding: 0;
		margin: 0;
		box-sizing: border-box;
}

.tabbar-container {
		position: fixed;
		z-index: 999;
		bottom: 0;
		left: 50%;
		transform: translateX(-50%);
		width: 100%;
		height: 108rpx;
		/* box-shadow: 0 0 5px    #8d6c36; */
		display: flex;
		align-items: center;
		justify-content: space-around;
		padding: 5rpx 0;
		color: #AAAAAA;
		background-color: #ffffff;
		box-shadow: 0rpx -1rpx 20rpx 0rpx rgba(80,79,79,0.1);
}

.tabbar-container .tabbar-item {
		width: 20%;
		height: 100rpx;
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
		text-align: center;
}

.tabbar-container .item-active {
		color: #00984A;
}

.tabbar-container .center-item {
		display: block;
		position: relative;
}

.tabbar-container .tabbar-item .item-top {
		width: 44rpx;
		height: 44rpx;
		margin-bottom: 4rpx;
		position: relative;
}
.tabbar-container .tabbar-item .item-top .item-uni-badge {
		position: absolute;
		top: -18rpx;
    right: -22rpx;
}
.tabbar-container .center-item .item-top {
		flex-shrink: 0;
		width: 94rpx;
		height: 94rpx;
		position: absolute;
    top: -30rpx;
		left: 30rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background-color: #FFFFFF;
    /* box-shadow: 0rpx -1rpx 20rpx 0rpx rgba(80,79,79,0.1); */
}

.tabbar-container .center-item .item-top::before {
  content: '';
  position: absolute;
  top: 24rpx;
  left: 0;
  right: 0;
  width: 100%;
	height: 100%;
	box-shadow: 0 0 20px 10px rgba(80, 79, 79, 0.1); /* 较大的阴影 */
	clip-path: circle(48% at 50% 16rpx); /* 裁剪路径,只显示上半圆 */
	z-index: -1;
}

.tabbar-container .center-item .item-top .bg-grey {
			width: 78rpx;
			height: 78rpx;
			display: flex;
			align-items: center;
			justify-content: center;
			border-radius: 50%;
			background-color: #F6F6F6;
		}

.tabbar-container .tabbar-item .item-top image {
		width: 44rpx;
		height: 44rpx;
}

.tabbar-container .center-item .item-top .bg-grey image {
		width: 44rpx;
		height: 44rpx;
}

.tabbar-container .tabbar-item .item-bottom {
		font-weight: bold;
		font-size: 22rpx;
		color: #AAAAAA;
}

.tabbar-container .center-item .item-bottom {
		position: absolute;
		bottom: 14rpx;
		left: 45rpx;
}
</style>

使用

方法1

在main.js里注册该组件,再在每个导航栏文件中添加

import Tabbar from "./components/tabbar/tabbar.vue"

Vue.component('tabbar', Tabbar)

方法2

每个导航栏对应文件单独引入并使用;全局关闭默认导航栏,或每个文件单独关闭

<Tabbar :current-page="2"></Tabbar> // 添加到页面中

import Tabbar from "./components/tabbar/tabbar.vue"

onShow(() => {
    uni.hideTabBar({
        animation: true
    });
})