168 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Vue
		
	
	
	
		
		
			
		
	
	
			168 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Vue
		
	
	
	
|  | <template> | ||
|  | 	<view class="custom-tab-bar"> | ||
|  | 		<view class="tab-bar-border"></view> | ||
|  | 		<view  | ||
|  | 			class="tab-bar-item"  | ||
|  | 			v-for="(item, index) in tabList"  | ||
|  | 			:key="index"  | ||
|  | 			@click="switchTab(item, index)" | ||
|  | 		> | ||
|  | 			<view class="item-container" :class="{ active: currentIndex === index }"> | ||
|  | 				<view class="icon-container"> | ||
|  | 					<image :src="currentIndex === index ? item.selectedIconPath : item.iconPath" class="tab-icon"></image> | ||
|  | 					<!-- 添加消息提示点 --> | ||
|  | 					<view v-if="item.isDot && index !== currentIndex" class="tab-badge"></view> | ||
|  | 					<view v-if="item.count && item.count > 0 && index !== currentIndex" class="tab-badge-count">{{item.count}}</view> | ||
|  | 				</view> | ||
|  | 				<text class="tab-text" :class="{ active: currentIndex === index }">{{ item.text }}</text> | ||
|  | 				 | ||
|  | 				<!-- 添加活跃项的动画效果 --> | ||
|  | 				<view v-if="currentIndex === index" class="active-indicator"></view> | ||
|  | 			</view> | ||
|  | 		</view> | ||
|  | 	</view> | ||
|  | </template> | ||
|  | 
 | ||
|  | <script> | ||
|  | 	export default { | ||
|  | 		data() { | ||
|  | 			return { | ||
|  | 				currentIndex: 0, | ||
|  | 				tabList: [] | ||
|  | 			} | ||
|  | 		}, | ||
|  | 		created() { | ||
|  | 			// 从Vuex获取tabBar配置
 | ||
|  | 			this.tabList = this.vuex_tabbar; | ||
|  | 			 | ||
|  | 			// 根据当前页面路径设置激活项
 | ||
|  | 			const pages = getCurrentPages(); | ||
|  | 			const currentPage = pages[pages.length - 1]; | ||
|  | 			const currentPath = '/' + currentPage.route; | ||
|  | 			 | ||
|  | 			this.tabList.forEach((item, index) => { | ||
|  | 				// 移除前导斜杠以匹配路由
 | ||
|  | 				const itemPath = item.pagePath.startsWith('/') ? item.pagePath.substring(1) : item.pagePath; | ||
|  | 				if (itemPath === currentPage.route) { | ||
|  | 					this.currentIndex = index; | ||
|  | 				} | ||
|  | 			}); | ||
|  | 		}, | ||
|  | 		methods: { | ||
|  | 			switchTab(item, index) { | ||
|  | 				if (this.currentIndex === index) return; | ||
|  | 				 | ||
|  | 				this.currentIndex = index; | ||
|  | 				// 移除前导斜杠如果存在
 | ||
|  | 				const pagePath = item.pagePath.startsWith('/') ? item.pagePath : '/' + item.pagePath; | ||
|  | 				uni.switchTab({ | ||
|  | 					url: pagePath | ||
|  | 				}); | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | </script> | ||
|  | 
 | ||
|  | <style lang="scss" scoped> | ||
|  | 	.custom-tab-bar { | ||
|  | 		position: fixed; | ||
|  | 		bottom: 0; | ||
|  | 		left: 0; | ||
|  | 		right: 0; | ||
|  | 		height: 56px; | ||
|  | 		background-color: #ffffff; | ||
|  | 		display: flex; | ||
|  | 		padding-bottom: env(safe-area-inset-bottom); | ||
|  | 		box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.05); | ||
|  | 		z-index: 999; | ||
|  | 		 | ||
|  | 		.tab-bar-border { | ||
|  | 			position: absolute; | ||
|  | 			left: 0; | ||
|  | 			top: 0; | ||
|  | 			width: 100%; | ||
|  | 			height: 1px; | ||
|  | 			background-color: #f5f5f5; | ||
|  | 			transform: scaleY(0.5); | ||
|  | 		} | ||
|  | 		 | ||
|  | 		.tab-bar-item { | ||
|  | 			flex: 1; | ||
|  | 			display: flex; | ||
|  | 			justify-content: center; | ||
|  | 			align-items: center; | ||
|  | 			height: 100%; | ||
|  | 			 | ||
|  | 			.item-container { | ||
|  | 				display: flex; | ||
|  | 				flex-direction: column; | ||
|  | 				align-items: center; | ||
|  | 				justify-content: center; | ||
|  | 				position: relative; | ||
|  | 				padding: 5px 0; | ||
|  | 				 | ||
|  | 				&.active { | ||
|  | 					transform: scale(1.05); | ||
|  | 					transition: all 0.2s ease; | ||
|  | 				} | ||
|  | 				 | ||
|  | 				.icon-container { | ||
|  | 					position: relative; | ||
|  | 					 | ||
|  | 					.tab-icon { | ||
|  | 						width: 24px; | ||
|  | 						height: 24px; | ||
|  | 						margin-bottom: 3px; | ||
|  | 					} | ||
|  | 					 | ||
|  | 					.tab-badge { | ||
|  | 						position: absolute; | ||
|  | 						top: -2px; | ||
|  | 						right: -2px; | ||
|  | 						width: 8px; | ||
|  | 						height: 8px; | ||
|  | 						border-radius: 50%; | ||
|  | 						background-color: #ff5252; | ||
|  | 					} | ||
|  | 					 | ||
|  | 					.tab-badge-count { | ||
|  | 						position: absolute; | ||
|  | 						top: -5px; | ||
|  | 						right: -5px; | ||
|  | 						min-width: 16px; | ||
|  | 						height: 16px; | ||
|  | 						border-radius: 8px; | ||
|  | 						background-color: #ff5252; | ||
|  | 						color: #ffffff; | ||
|  | 						font-size: 10px; | ||
|  | 						line-height: 16px; | ||
|  | 						text-align: center; | ||
|  | 						padding: 0 4px; | ||
|  | 					} | ||
|  | 				} | ||
|  | 				 | ||
|  | 				.tab-text { | ||
|  | 					font-size: 12px; | ||
|  | 					color: #999999; | ||
|  | 					line-height: 1.2; | ||
|  | 					 | ||
|  | 					&.active { | ||
|  | 						color: #2979FF; | ||
|  | 						font-weight: 500; | ||
|  | 					} | ||
|  | 				} | ||
|  | 				 | ||
|  | 				.active-indicator { | ||
|  | 					position: absolute; | ||
|  | 					bottom: -8px; | ||
|  | 					left: 50%; | ||
|  | 					transform: translateX(-50%); | ||
|  | 					width: 16px; | ||
|  | 					height: 3px; | ||
|  | 					background-color: #2979FF; | ||
|  | 					border-radius: 3px; | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | </style>  |