2025-09-24 11:37:39 +08:00

361 lines
6.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="custom-tabbar">
<view
class="tabbar-item"
v-for="(item, index) in tabList"
:key="index"
@click="switchTab(index, item)"
:class="{ active: currentTab === index }"
>
<!-- 图标容器 -->
<view class="icon-container">
<image class="img" :src="currentTab === index ? item.activeIcon : item.icon" alt="" />
<!-- 徽章 -->
<!-- <view class="badge" v-if="item.badge && item.badge > 0">
<uni-badge
:text="item.badge > 99 ? '99+' : item.badge.toString()"
type="error"
size="small"
></uni-badge>
</view> -->
<!-- 红点 -->
<!-- <view class="red-dot" v-if="item.showRedDot"></view> -->
</view>
<!-- 文字 -->
<text class="tab-text" :class="{ active: currentTab === index }">
{{ item.text }}
</text>
<!-- 动画效果 -->
<!-- <view class="active-indicator" v-if="currentTab === index"></view> -->
</view>
</view>
</template>
<script setup>
import { ref, reactive, onMounted, nextTick } from 'vue';
import { onShow, onLoad } from "@dcloudio/uni-app";
import home from '@/static/home_nor.png'
import homeOn from '@/static/home_sel.png'
import classroom from "@/static/classroom.png"
import classroomOn from "@/static/classroomOn.png"
import live from "@/static/live.png"
import liveOn from "@/static/liveOn.png"
import education from '@/static/education.png'
import educationOn from '@/static/educationOn.png'
import my from '@/static/my.png'
import myOn from '@/static/myOn.png'
// 定义props
const props = defineProps({
// 可以添加自定义props
});
// 定义emits
const emit = defineEmits(['tabChange']);
// 当前选中的tab
const currentTab = ref(0);
// tabbar数据
const tabList = reactive([
{
icon: home,
activeIcon: homeOn,
text: '首页',
color: '#999999',
activeColor: '#007aff',
badge: 0,
showRedDot: false,
pagePath: '/pages/index/index'
},
{
icon: classroom,
activeIcon: classroomOn,
text: '患教学堂',
color: '#999999',
activeColor: '#007aff',
badge:0,
showRedDot: false,
pagePath: '/pages/patientClass/patientClass'
},
{
icon: live,
activeIcon: liveOn,
text: '会议·直播',
color: '#999999',
activeColor: '#007aff',
badge: 0,
showRedDot: false,
pagePath: '/pages/live/live'
},
{
icon: education,
activeIcon:educationOn,
text: '继续教育',
color: '#999999',
activeColor: '#007aff',
badge: 0,
showRedDot: false,
pagePath: '/pages/education/education'
},
{
icon: my,
activeIcon: myOn,
text: '我的',
color: '#999999',
activeColor: '#007aff',
badge: 0,
showRedDot: false,
pagePath: '/pages/my/my'
}
]);
// 切换tab
const switchTab = (index, item) => {
if (currentTab.value === index) return;
// 更新当前tab
currentTab.value = index;
// 清除红点
if (item.showRedDot) {
item.showRedDot = false;
}
// 页面跳转
uni.redirectTo({
url: item.pagePath,
fail: () => {
// 如果页面不存在使用navigateTo
uni.navigateTo({
url: item.pagePath,
fail: () => {
}
});
}
});
// 触发父组件事件
emit('tabChange', {
index,
item
});
};
// 设置徽章数量
const setBadge = (index, count) => {
if (index >= 0 && index < tabList.length) {
tabList[index].badge = count;
}
};
// 显示红点
const showRedDot = (index) => {
if (index >= 0 && index < tabList.length) {
tabList[index].showRedDot = true;
}
};
// 隐藏红点
const hideRedDot = (index) => {
if (index >= 0 && index < tabList.length) {
tabList[index].showRedDot = false;
}
};
// 设置当前tab
const setCurrentTab = (index) => {
if (index >= 0 && index < tabList.length) {
currentTab.value = index;
}
};
// 获取当前tab信息
const getCurrentTab = () => {
return {
index: currentTab.value,
item: tabList[currentTab.value]
};
};
// 更新tabbar数据
const updateTabList = (newTabList) => {
if (Array.isArray(newTabList)) {
tabList.splice(0, tabList.length, ...newTabList);
}
};
// 暴露方法给父组件
defineExpose({
setBadge,
showRedDot,
hideRedDot,
setCurrentTab,
getCurrentTab,
updateTabList,
currentTab,
tabList
});
// 页面加载时获取当前页面路径
onLoad(() => {
nextTick(() => {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const currentPath = '/' + currentPage.route;
// 根据当前页面路径设置选中的tab
const tabIndex = tabList.findIndex(item => item.pagePath === currentPath);
if (tabIndex !== -1) {
currentTab.value = tabIndex;
}
});
});
// 页面显示时更新状态
onShow(() => {
// 可以在这里更新徽章数量等状态
console.log('Tabbar onShow - 当前tab:', currentTab.value);
});
// 组件挂载后
onMounted(() => {
console.log('Tabbar组件已挂载');
});
</script>
<style scoped>
.custom-tabbar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
overflow-x: hidden;
height: 120rpx;
background-color: #ffffff;
display: flex;
justify-content: space-around;
align-items: center;
border-top: 2rpx solid #f0f0f0;
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.1);
z-index: 999;
padding-bottom: env(safe-area-inset-bottom);
}
.tabbar-item {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex: 1;
height: 100%;
transition: all 0.3s ease;
}
.img{
width: 46rpx;
height: 46rpx;
}
.icon-container {
width:100%;
overflow-x: hidden;
position: relative;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 8rpx;
}
.badge {
position: absolute;
top: -8rpx;
right: -8rpx;
z-index: 10;
}
.red-dot {
position: absolute;
top: -4rpx;
right: -4rpx;
width: 16rpx;
height: 16rpx;
background-color: #ff0000;
border-radius: 50%;
border: 2rpx solid #ffffff;
z-index: 10;
}
.tab-text {
font-size: 20rpx;
color: #999999;
transition: all 0.3s ease;
font-weight: 400;
}
.tab-text.active {
color: #8B2316;
font-weight: 600;
transform: scale(1.05);
}
.active-indicator {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 40rpx;
height: 4rpx;
background: linear-gradient(90deg, #007aff, #0056b3);
border-radius: 2rpx;
animation: slideIn 0.3s ease;
}
@keyframes slideIn {
from {
width: 0;
opacity: 0;
}
to {
width: 40rpx;
opacity: 1;
}
}
/* 点击效果 */
.tabbar-item:active {
transform: scale(0.95);
}
/* 响应式设计 */
@media (max-width: 750rpx) {
.custom-tabbar {
height: 100rpx;
}
.tab-text {
font-size: 18rpx;
}
}
/* 深色模式支持 */
@media (prefers-color-scheme: dark) {
.custom-tabbar {
background-color: #1c1c1e;
border-top-color: #2c2c2e;
}
.tab-text {
color: #8e8e93;
}
.tab-text.active {
color: #0a84ff;
}
}
</style>