From df4dd9f030ac4e830d93f2f64e2379a9b7dad278 Mon Sep 17 00:00:00 2001
From: xiangpei <xiangpei@timesnew.cn>
Date: 星期三, 25 六月 2025 20:41:20 +0800
Subject: [PATCH] 自定义顶部组件、顶部tab对应页面接入该组件

---
 pages.json                                 |   34 +++---
 pages/mine/activity/reportActivity.vue     |   25 ++++
 components/TopBar.vue                      |  142 ++++++++++++++++++++++++++++
 pages/health/healthVideo.vue               |    8 +
 pages/tabbar/index/home.vue                |   21 ++++
 pages/commodity-square/commoditySquare.vue |   27 ++++
 6 files changed, 234 insertions(+), 23 deletions(-)

diff --git a/components/TopBar.vue b/components/TopBar.vue
new file mode 100644
index 0000000..64913f8
--- /dev/null
+++ b/components/TopBar.vue
@@ -0,0 +1,142 @@
+<template>
+	<view class="top-bar" :style="{paddingTop: statusBarHeight + 'px'}">
+		<view class="top-bar-content">
+			<!-- 鏍囬鍒楄〃 -->
+			<scroll-view class="title-scroll" scroll-x="true" scroll-with-animation :scroll-left="scrollLeft">
+				<view class="title-container">
+					<view 
+						v-for="(item, index) in titleList" 
+						:key="index"
+						:class="{active: selectedTitleIndex === item.index, 'title-item': true}"
+						@click="changeTab(item)"
+					>
+						<text>{{item.title}}</text>
+						<view class="underline" v-if="selectedTitleIndex === item.index"></view>
+					</view>
+				</view>
+			</scroll-view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name:"TopBar",
+		props: {
+			selectedTitleIndex: {
+				type: String,
+				default: 'home'
+			}
+		},
+		data() {
+			return {
+				statusBarHeight: 0,
+				scrollLeft: 0,
+				titleList: [
+					{
+						index: 'home',
+						pagePath: '/pages/tabbar/index/home',
+						title: '鎺ㄨ崘'
+					},
+					{
+						index: 'shop',
+						pagePath: '/pages/commodity-square/commoditySquare',
+						title: '鍟嗗搧骞垮満'
+					},
+					{
+						index: 'activity',
+						pagePath: '/pages/mine/activity/reportActivity',
+						title: '娲诲姩'
+					},
+					{
+						index: 'health',
+						pagePath: '/pages/health/healthVideo',
+						title: '澶у仴搴�'
+					}
+				]
+			};
+		},
+		created() {
+			// 鑾峰彇鐘舵�佹爮楂樺害
+			const systemInfo = uni.getSystemInfoSync();
+			this.statusBarHeight = systemInfo.statusBarHeight;
+		},
+		methods: {
+			changeTab(titleObj) {
+				console.log("鐐瑰嚮椤堕儴瀵艰埅", titleObj);
+				if (titleObj.index !== this.selectedTitleIndex) {
+					this.$emit("changeTab", titleObj);
+					// 璁$畻婊氬姩浣嶇疆浣垮綋鍓嶉�変腑椤瑰眳涓�
+					this.$nextTick(() => {
+						const query = uni.createSelectorQuery().in(this);
+						query.select(`.title-item[data-index="${titleObj.index}"]`).boundingClientRect();
+						query.select('.title-scroll').boundingClientRect();
+						query.exec(res => {
+							if (res[0] && res[1]) {
+								const itemLeft = res[0].left;
+								const scrollWidth = res[1].width;
+								const itemWidth = res[0].width;
+								this.scrollLeft = itemLeft - (scrollWidth - itemWidth) / 2;
+							}
+						});
+					});
+				}
+			}
+		}
+	}
+</script>
+
+<style>
+	.top-bar {
+			position: fixed;
+			top: 0;
+			left: 0;
+			right: 0;
+			z-index: 999;
+		}
+		
+		.top-bar .top-bar-content {
+			box-sizing: border-box;
+			display: flex;
+			align-items: center;
+		}
+		
+		.top-bar .title-scroll {
+			width: 100%;
+			height: 80rpx;
+			white-space: nowrap;
+		}
+		
+		.top-bar .title-scroll .title-container {
+			display: inline-flex;
+			height: 100%;
+			align-items: center;
+		}
+		
+		.top-bar .title-scroll .title-container .title-item {
+			position: relative;
+			padding: 0 24rpx;
+			font-size: 32rpx;
+			color: white;
+			height: 100%;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			flex-direction: column;
+		}
+		
+		.top-bar .title-scroll .title-container .title-item.active {
+			font-weight: 500;
+		}
+		
+		.top-bar .title-scroll .title-container .title-item.active .underline {
+			position: absolute;
+			bottom: 4rpx;
+			left: 50%;
+			transform: translateX(-50%);
+			width: calc(100% - 76rpx);
+			height: 4rpx;
+			background-color: white;
+			border-radius: 4rpx;
+		}
+</style>
\ No newline at end of file
diff --git a/pages.json b/pages.json
index a606eaf..49495a3 100644
--- a/pages.json
+++ b/pages.json
@@ -65,10 +65,10 @@
 		{
 			// "path": "pages/tabbar/category/category",
 			"path": "pages/commodity-square/commoditySquare",
-		
+
 			"style": {
 				"navigationBarTitleText": "鍟嗗搧骞垮満",
-				// "navigationStyle": "custom", // 闅愯棌绯荤粺瀵艰埅鏍�
+				"navigationStyle": "custom", // 闅愯棌绯荤粺瀵艰埅鏍�
 				"navigationBarTextStyle": "black",
 				// "disableScroll": true,
 				"bounce": "none",
@@ -749,6 +749,7 @@
 					"style": {
 						"navigationBarTitleText": "娲诲姩",
 						"enablePullDownRefresh": true, //涓嬫媺鍒锋柊
+						"navigationStyle": "custom", // 闅愯棌椤堕儴瀵艰埅鏍�
 						"componentPlaceholder": {
 							"u-form": "view",
 							"u-form-item": "view",
@@ -987,7 +988,7 @@
 				},
 				{
 					"path" : "video-goods-detail",
-					"style" : 
+					"style" :
 					{
 						"navigationBarTitleText" : "瑙嗛鎺ㄨ崘鍟嗗搧",
 						"componentPlaceholder": {
@@ -1435,7 +1436,8 @@
 			"pages": [{
 				"path": "healthVideo",
 				"style": {
-					"navigationBarTitleText": "澶у仴搴�"
+					"navigationBarTitleText": "澶у仴搴�",
+					"navigationStyle": "custom"
 				}
 			}]
 		},
@@ -1452,13 +1454,13 @@
 			"root": "pages/supplier",
 			"pages": [{
 				"path" : "suppler-order/suppler-order",
-				"style" : 
+				"style" :
 				{
 					"navigationBarTitleText" : ""
 				}
 			}]
 		}
-		
+
 		// ,
 		// {
 		// 	"root": "pages/commodity-square",
@@ -1496,13 +1498,13 @@
 				"selectedIconPath": "static/tabbar/home-s.png",
 				"text": "棣栭〉"
 			},
-			{
-				// "pagePath": "pages/tabbar/category/category",
-				"pagePath": "pages/commodity-square/commoditySquare",
-				"iconPath": "static/tabbar/category.png",
-				"selectedIconPath": "static/tabbar/category-s.png",
-				"text": "鍟嗗煄"
-			},
+			// {
+			// 	// "pagePath": "pages/tabbar/category/category",
+			// 	"pagePath": "pages/commodity-square/commoditySquare",
+			// 	"iconPath": "static/tabbar/category.png",
+			// 	"selectedIconPath": "static/tabbar/category-s.png",
+			// 	"text": "鍟嗗煄"
+			// },
 			{
 				"pagePath": "pages/tabbar/video/video",
 				"iconPath": "static/tabbar/video.png",
@@ -1522,11 +1524,11 @@
 			}
 		]
 	},
-	// #todo 涓轰粈涔堣娉ㄩ噴condition涓嬩唬鐮侊紵 
+	// #todo 涓轰粈涔堣娉ㄩ噴condition涓嬩唬鐮侊紵
 	// IOS plus.runtime.arguments 娣诲姞 condition鑺傜偣鍚庯紝 妗嗘灦浼氫慨鏀� runtime.arguments
 	// 浼氬奖鍝嶄粈涔堝姛鑳斤紵
 	//    -鍦╤5涓敜閱抋pp浼氫竴鐩磋繑鍥為粯璁ゅ�� {"name":"","path":"","query":"","id":0}
-	"condition": { //妯″紡閰嶇疆锛屼粎寮�鍙戞湡闂寸敓鏁�   
+	"condition": { //妯″紡閰嶇疆锛屼粎寮�鍙戞湡闂寸敓鏁�
 		// "current": 0, //褰撳墠婵�娲荤殑妯″紡(list 鐨勭储寮曢」)
 		// "list": [{
 		// 	"name": "", //妯″紡鍚嶇О
@@ -1534,4 +1536,4 @@
 		// 	"query": "" //鍚姩鍙傛暟锛屽湪椤甸潰鐨刼nLoad鍑芥暟閲岄潰寰楀埌
 		// }]
 	}
-}
\ No newline at end of file
+}
diff --git a/pages/commodity-square/commoditySquare.vue b/pages/commodity-square/commoditySquare.vue
index d7c7fad..e83e4e5 100644
--- a/pages/commodity-square/commoditySquare.vue
+++ b/pages/commodity-square/commoditySquare.vue
@@ -1,5 +1,6 @@
 <template>
 	<view class="container">
+		<top-bar selectedTitleIndex="shop" @changeTab="topBarChange" class="topBar"></top-bar>
 		<input type="text" v-show="false" v-model="flushDom" />
 		<view class="search">
 			<u-search class="nav-search" @blur='searchGoods' placeholder="鎼滅储鍟嗗搧" :show-action="false"></u-search>
@@ -12,7 +13,7 @@
 						:controls="false" object-fit="contain" :show-play-btn="false" :show-center-play-btn="false"
 						@loadedmetadata="getvideoInfo($event,'goodsList1',index)" :ref="'video'+item.id"
 						:style="{width:item.width,height:item.height}"></video> -->
-					<image :src="item.thumbnail" 
+					<image :src="item.thumbnail"
 						mode="aspectFill" class="goodsImg">
 					</image>
 					<view class="goodsInfo">
@@ -31,7 +32,7 @@
 						:controls="false" object-fit="contain" :show-play-btn="false" :show-center-play-btn="false"
 						@loadedmetadata="getvideoInfo($event,'goodsList2',index)" :ref="'video'+item.id"
 						:style="{width:item.width,height:item.height}"></video> -->
-					<image :src="item.thumbnail" 
+					<image :src="item.thumbnail"
 						mode="aspectFill" class="goodsImg">
 					</image>
 					<view class="goodsInfo">
@@ -60,11 +61,11 @@
 		</view>
 		<view style="display: flex;align-items: center;justify-content: center;margin-top: 20rpx;" v-if="canLoadMore">
 			娌℃湁鏇村鏁版嵁浜�.................</view>
-		<custom-tabbar bgColor="#ffffff" selected="shop"></custom-tabbar>
 	</view>
 </template>
 
 <script>
+	import TopBar from "@/components/TopBar.vue";
 	import {
 		getCategoryList,
 		getGoodsList
@@ -73,6 +74,7 @@
 		getSTSToken
 	} from '@/api/common.js'
 	export default {
+		components: {TopBar},
 		data() {
 			return {
 				//璁板綍涓ゅ垪楂樺害
@@ -104,6 +106,17 @@
 			}
 		},
 		methods: {
+			topBarChange(titleObj) {
+				if (titleObj.index === 'home') {
+					uni.switchTab({
+						url: titleObj.pagePath
+					});
+				} else {
+					uni.redirectTo({
+						url: titleObj.pagePath
+					});
+				}
+			},
 			async searchGoods(keyWard) {
 				this.getGoodsParam.keyword = keyWard
 				this.getGoodsParam.pageNumber = 1
@@ -393,4 +406,10 @@
 		color: red;
 		font-weight: bold;
 	}
-</style>
\ No newline at end of file
+	.topBar {
+		position: fixed;
+		top: 20rpx;
+		left: 20rpx;
+		z-index: 1000
+	}
+</style>
diff --git a/pages/health/healthVideo.vue b/pages/health/healthVideo.vue
index 34d7f92..4ac5030 100644
--- a/pages/health/healthVideo.vue
+++ b/pages/health/healthVideo.vue
@@ -1,5 +1,6 @@
 <template>
   <view class="video-container">
+    <top-bar selectedTitleIndex="health" @changeTab="topBarChange" class="topBar"></top-bar>
 	<!-- 瑙嗛鍔犺浇 -->
 	<zero-loading v-show="videoLoading" type="circle" color="#0ebd57" text=""></zero-loading>
     <!-- 瑙嗛鍒楄〃 -->
@@ -241,6 +242,7 @@
 </template>
 
 <script>
+import TopBar from "@/components/TopBar.vue";
 import { getHealthRecommendVideos, savePlayRecord, subscribe, getVideoComments, addVideoComment, thubmsUpComment, cancelThubmsUpComment } from "@/api/video.js";
 import { changeCollect } from "@/api/collect.js";
 import { saveShare, saveShareClickRecord } from "@/api/share.js";
@@ -1361,4 +1363,10 @@
 	.custom-share-btn::after {
 	  border: none;
 	}
+	.topBar {
+		position: fixed;
+		top: 20rpx;
+		left: 20rpx;
+		z-index: 1000
+	}
 </style>
diff --git a/pages/mine/activity/reportActivity.vue b/pages/mine/activity/reportActivity.vue
index b035663..017f929 100644
--- a/pages/mine/activity/reportActivity.vue
+++ b/pages/mine/activity/reportActivity.vue
@@ -1,7 +1,7 @@
 <template>
 	<view class="wrapper">
-		
-		
+		<top-bar selectedTitleIndex="activity" @changeTab="topBarChange" class="topBar"></top-bar>
+
 		<view style="height: 100rpx"></view>
 		<!-- 鍐呭鍖哄煙 -->
 		<scroll-view scroll-y class="content" style="height: 40vh;" @scrolltolower="loadMore" :lower-threshold="100">
@@ -47,9 +47,11 @@
 </template>
 
 <script>
+	import TopBar from "@/components/TopBar.vue";
 	import '@/components/uview-components/uview-ui';
 	import {getActivityReportList} from '@/api/activity.js';
 	export default {
+		components: {TopBar},
 		data() {
 			return {
 				columns: [
@@ -74,6 +76,17 @@
 			this.getActivityList();
 		},
 		methods: {
+			topBarChange(titleObj) {
+				if (titleObj.index === 'home') {
+					uni.switchTab({
+						url: titleObj.pagePath
+					});
+				} else {
+					uni.redirectTo({
+						url: titleObj.pagePath
+					});
+				}
+			},
 			/**
 			 * 涓嬫媺鍒锋柊鏃�
 			 */
@@ -367,4 +380,10 @@
 			font-size: 28rpx;
 		}
 	}
-</style>
\ No newline at end of file
+	.topBar {
+		position: fixed;
+		top: 20rpx;
+		left: 20rpx;
+		z-index: 1000
+	}
+</style>
diff --git a/pages/tabbar/index/home.vue b/pages/tabbar/index/home.vue
index a2cf82d..4e2f810 100644
--- a/pages/tabbar/index/home.vue
+++ b/pages/tabbar/index/home.vue
@@ -1,5 +1,6 @@
 <template>
   <view class="video-container">
+	<top-bar selectedTitleIndex="home" @changeTab="topBarChange" class="topBar"></top-bar>
 	<!-- 瑙嗛鍔犺浇 -->
 	<zero-loading v-show="videoLoading" type="circle" color="#0ebd57" text=""></zero-loading>
     <!-- 瑙嗛鍒楄〃 -->
@@ -247,7 +248,10 @@
 import { silentLogin } from "@/api/connect.js";
 import { getUserInfo } from "@/api/members";
 import storage from "@/utils/storage.js";
+import TopBar from "@/components/TopBar.vue";
+
 export default {
+  components: {TopBar},
   computed: {
 	    hasPlayTime() {
 	      return this.sliderFormatTime(this.progress > 0 ? this.duration * this.progress / 100 : 0);
@@ -379,6 +383,17 @@
   	}
   },
   methods: {
+	  topBarChange(titleObj) {
+		if (titleObj.index === 'home') {
+			uni.switchTab({
+				url: titleObj.pagePath
+			});
+		} else {
+			uni.redirectTo({
+				url: titleObj.pagePath
+			});
+		}
+	  },
 	  // 闈欓粯鐧诲綍
 	  wxSilentLogin(callback) {
 		  //鑾峰彇code
@@ -1361,4 +1376,10 @@
 	.custom-share-btn::after {
 	  border: none;
 	}
+	.topBar {
+		position: fixed;
+		top: 20rpx;
+		left: 20rpx;
+		z-index: 1000
+	}
 </style>

--
Gitblit v1.8.0