8.21提交
This commit is contained in:
@@ -0,0 +1,367 @@
|
||||
<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">
|
||||
<!-- <uni-icons
|
||||
:type="currentTab === index ? item.activeIcon : item.icon"
|
||||
:size="currentTab === index ? 28 : 24"
|
||||
:color="currentTab === index ? item.activeColor : item.color"
|
||||
></uni-icons> -->
|
||||
<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: 5,
|
||||
showRedDot: false,
|
||||
pagePath: '/pages/education/education'
|
||||
},
|
||||
{
|
||||
icon: live,
|
||||
activeIcon: liveOn,
|
||||
text: '会议·直播',
|
||||
color: '#999999',
|
||||
activeColor: '#007aff',
|
||||
badge: 0,
|
||||
showRedDot: true,
|
||||
pagePath: '/pages/meeting/meeting'
|
||||
},
|
||||
{
|
||||
icon: education,
|
||||
activeIcon:educationOn,
|
||||
text: '继续教育',
|
||||
color: '#999999',
|
||||
activeColor: '#007aff',
|
||||
badge: 12,
|
||||
showRedDot: false,
|
||||
pagePath: '/pages/education/continuing'
|
||||
},
|
||||
{
|
||||
icon: my,
|
||||
activeIcon: myOn,
|
||||
text: '我的',
|
||||
color: '#999999',
|
||||
activeColor: '#007aff',
|
||||
badge: 0,
|
||||
showRedDot: false,
|
||||
pagePath: '/pages/profile/profile'
|
||||
}
|
||||
]);
|
||||
|
||||
// 切换tab
|
||||
const switchTab = (index, item) => {
|
||||
if (currentTab.value === index) return;
|
||||
|
||||
// 更新当前tab
|
||||
currentTab.value = index;
|
||||
|
||||
// 清除红点
|
||||
if (item.showRedDot) {
|
||||
item.showRedDot = false;
|
||||
}
|
||||
|
||||
// 页面跳转
|
||||
uni.switchTab({
|
||||
url: item.pagePath,
|
||||
fail: () => {
|
||||
// 如果页面不存在,使用navigateTo
|
||||
uni.navigateTo({
|
||||
url: item.pagePath,
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: '页面开发中',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 触发父组件事件
|
||||
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>
|
||||
Reference in New Issue
Block a user