From f26f29d84e0a68831a6af14dab3eec5500496d2e Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期三, 28 五月 2025 16:48:52 +0800
Subject: [PATCH] 初始化项目

---
 uview-ui/components/u-tabbar/u-tabbar.vue |  330 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 330 insertions(+), 0 deletions(-)

diff --git a/uview-ui/components/u-tabbar/u-tabbar.vue b/uview-ui/components/u-tabbar/u-tabbar.vue
new file mode 100644
index 0000000..2e1b6a2
--- /dev/null
+++ b/uview-ui/components/u-tabbar/u-tabbar.vue
@@ -0,0 +1,330 @@
+<template>
+	<view v-if="show" class="u-tabbar" @touchmove.stop.prevent="() => {}">
+		<view class="u-tabbar__content safe-area-inset-bottom" :style="{
+			height: $u.addUnit(height),
+			backgroundColor: bgColor,
+		}" :class="{
+			'u-border-top': borderTop
+		}">
+			<view class="u-tabbar__content__item" v-for="(item, index) in list" :key="index" :class="{
+				'u-tabbar__content__circle': midButton &&item.midButton
+			}" @tap.stop="clickHandler(index)" :style="{
+				backgroundColor: bgColor
+			}">
+				<view :class="[
+					midButton && item.midButton ? 'u-tabbar__content__circle__button' : 'u-tabbar__content__item__button'
+				]">
+					<u-icon
+						:size="midButton && item.midButton ? midButtonSize : iconSize"
+						:name="elIconPath(index)"
+						img-mode="scaleToFill"
+						:color="elColor(index)"
+						:custom-prefix="item.customIcon ? 'custom-icon' : 'uicon'"
+					></u-icon>
+					<u-badge :count="item.count" :is-dot="item.isDot"
+						v-if="item.count || item.isDot"
+						:offset="[-2, getOffsetRight(item.count, item.isDot)]"
+					></u-badge>
+				</view>
+				<view class="u-tabbar__content__item__text" :style="{
+					color: elColor(index)
+				}">
+					<text class="u-line-1">{{item.text}}</text>
+				</view>
+			</view>
+			<view v-if="midButton" class="u-tabbar__content__circle__border" :class="{
+				'u-border': borderTop,
+			}" :style="{
+				backgroundColor: bgColor,
+				left: midButtonLeft
+			}">
+			</view>
+		</view>
+		<!-- 杩欓噷鍔犱笂涓�涓�48rpx鐨勯珮搴�,鏄负浜嗗楂樻湁鍑歌捣鎸夐挳鏃剁殑闃插闄烽珮搴�(涔熷嵆鎸夐挳鍑稿嚭鏉ラ儴鍒嗙殑楂樺害) -->
+		<view class="u-fixed-placeholder safe-area-inset-bottom" :style="{
+				height: `calc(${$u.addUnit(height)} + ${midButton ? 48 : 0}rpx)`,
+			}"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			// 鏄剧ず涓庡惁
+			show: {
+				type: Boolean,
+				default: true
+			},
+			// 閫氳繃v-model缁戝畾current鍊�
+			value: {
+				type: [String, Number],
+				default: 0
+			},
+			// 鏁翠釜tabbar鐨勮儗鏅鑹�
+			bgColor: {
+				type: String,
+				default: '#ffffff'
+			},
+			// tabbar鐨勯珮搴︼紝榛樿50px锛屽崟浣嶄换鎰忥紝濡傛灉涓烘暟鍊硷紝鍒欎负rpx鍗曚綅
+			height: {
+				type: [String, Number],
+				default: '50px'
+			},
+			// 闈炲嚫璧峰浘鏍囩殑澶у皬锛屽崟浣嶄换鎰忥紝鏁板�奸粯璁px
+			iconSize: {
+				type: [String, Number],
+				default: 40
+			},
+			// 鍑歌捣鐨勫浘鏍囩殑澶у皬锛屽崟浣嶄换鎰忥紝鏁板�奸粯璁px
+			midButtonSize: {
+				type: [String, Number],
+				default: 90
+			},
+			// 婵�娲绘椂鐨勬紨绀猴紝鍖呮嫭瀛椾綋鍥炬爣锛屾彁绀烘枃瀛楃瓑鐨勬紨绀�
+			activeColor: {
+				type: String,
+				default: '#303133'
+			},
+			// 鏈縺娲绘椂鐨勯鑹�
+			inactiveColor: {
+				type: String,
+				default: '#606266'
+			},
+			// 鏄惁鏄剧ず涓儴鐨勫嚫璧锋寜閽�
+			midButton: {
+				type: Boolean,
+				default: false
+			},
+			// 閰嶇疆鍙傛暟
+			list: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			// 鍒囨崲鍓嶇殑鍥炶皟
+			beforeSwitch: {
+				type: Function,
+				default: null
+			},
+			// 鏄惁鏄剧ず椤堕儴鐨勬í绾�
+			borderTop: {
+				type: Boolean,
+				default: true
+			},
+			// 鏄惁闅愯棌鍘熺敓tabbar
+			hideTabBar: {
+				type: Boolean,
+				default: true
+			},
+		},
+		data() {
+			return {
+				// 鐢变簬瀹夊崜澶彍浜嗭紝閫氳繃css灞呬腑鍑歌捣鎸夐挳鐨勫灞傚厓绱犳湁璇樊锛屾晠閫氳繃js璁$畻灏嗗叾灞呬腑
+				midButtonLeft: '50%',
+				pageUrl: '', // 褰撳墠椤甸潰URL
+			}
+		},
+		created() {
+			// 鏄惁闅愯棌鍘熺敓tabbar
+			if(this.hideTabBar) uni.hideTabBar();
+			// 鑾峰彇寮曞叆浜唘-tabbar椤甸潰鐨勮矾鐢卞湴鍧�锛岃鍦板潃娌℃湁璺緞鍓嶉潰鐨�"/"
+			let pages = getCurrentPages();
+			// 椤甸潰鏍堜腑鐨勬渶鍚庝竴涓嵆涓洪」涓哄綋鍓嶉〉闈紝route灞炴�т负椤甸潰璺緞
+			this.pageUrl = pages[pages.length - 1].route;
+		},
+		computed: {
+			elIconPath() {
+				return (index) => {
+					// 鍘嗛亶u-tabbar鐨勬瘡涓�椤筰tem鏃讹紝鍒ゆ柇鏄惁浼犲叆浜唒agePath鍙傛暟锛屽鏋滀紶鍏ヤ簡
+					// 鍜宒ata涓殑pageUrl鍙傛暟瀵规瘮锛屽鏋滅浉绛夛紝鍗冲彲鍒ゆ柇褰撳墠鐨刬tem瀵瑰簲褰撳墠鐨則abbar椤甸潰锛岃缃珮浜浘鏍�
+					// 閲囩敤杩欎釜鏂规硶锛屽彲浠ユ棤闇�浣跨敤v-model缁戝畾鐨剉alue鍊�
+					let pagePath = this.list[index].pagePath;
+					// 濡傛灉瀹氫箟浜唒agePath灞炴�э紝鎰忓懗鐫�浣跨敤绯荤粺鑷甫tabbar鏂规锛屽惁鍒欎娇鐢ㄤ竴涓〉闈㈢敤鍑犱釜缁勪欢妯℃嫙tabbar椤甸潰鐨勬柟妗�
+					// 杩欎袱涓柟妗堝澶勭悊tabbar item鐨勬縺娲讳笌鍚︽柟寮忎笉涓�鏍�
+					if(pagePath) {
+						if(pagePath == this.pageUrl || pagePath == '/' + this.pageUrl) {
+							return this.list[index].selectedIconPath;
+						} else {
+							return this.list[index].iconPath;
+						}
+					} else {
+						// 鏅�氭柟妗堜腑锛岀储寮曠瓑浜巚-model鍊兼椂锛屽嵆涓烘縺娲婚」
+						return index == this.value ? this.list[index].selectedIconPath : this.list[index].iconPath
+					}
+				}
+			},
+			elColor() {
+				return (index) => {
+					// 鍒ゆ柇鏂规硶鍚岀悊浜巈lIconPath
+					let pagePath = this.list[index].pagePath;
+					if(pagePath) {
+						if(pagePath == this.pageUrl || pagePath == '/' + this.pageUrl) return this.activeColor;
+						else return this.inactiveColor;
+					} else {
+						return index == this.value ? this.activeColor : this.inactiveColor;
+					}
+				}
+			}
+		},
+		mounted() {
+			this.midButton && this.getMidButtonLeft();
+		},
+		methods: {
+			async clickHandler(index) {
+				if(this.beforeSwitch && typeof(this.beforeSwitch) === 'function') {
+					// 鎵ц鍥炶皟锛屽悓鏃朵紶鍏ョ储寮曞綋浣滃弬鏁�
+					// 鍦ㄥ井淇★紝鏀粯瀹濈瓑鐜(H5姝e父)锛屼細瀵艰嚧鐖剁粍浠跺畾涔夌殑customBack()鍑芥暟浣撲腑鐨則his鍙樻垚瀛愮粍浠剁殑this
+					// 閫氳繃bind()鏂规硶锛岀粦瀹氱埗缁勪欢鐨則his锛岃this.customBack()鐨則his涓虹埗缁勪欢鐨勪笂涓嬫枃
+					let beforeSwitch = this.beforeSwitch.bind(this.$u.$parent.call(this))(index);
+					// 鍒ゆ柇鏄惁杩斿洖浜唒romise
+					if (!!beforeSwitch && typeof beforeSwitch.then === 'function') {
+						await beforeSwitch.then(res => {
+							// promise杩斿洖鎴愬姛锛�
+							this.switchTab(index);
+						}).catch(err => {
+
+						})
+					} else if(beforeSwitch === true) {
+						// 濡傛灉杩斿洖true
+						this.switchTab(index);
+					}
+				} else {
+					this.switchTab(index);
+				}
+			},
+			// 鍒囨崲tab
+			switchTab(index) {
+				// 鍙戝嚭浜嬩欢鍜屼慨鏀箆-model缁戝畾鐨勫��
+				this.$emit('change', index);
+				// 濡傛灉鏈夐厤缃畃agePath灞炴�э紝浣跨敤uni.switchTab杩涜璺宠浆
+				if(this.list[index].pagePath) {
+					uni.switchTab({
+						url: this.list[index].pagePath
+					})
+				} else {
+					// 濡傛灉閰嶇疆浜唒apgePath灞炴�э紝灏嗕笉浼氬弻鍚戠粦瀹歷-model浼犲叆鐨剉alue鍊�
+					// 鍥犱负杩欎釜妯″紡涓嬶紝涓嶅啀闇�瑕乿-model缁戝畾鐨剉alue鍊间簡锛岃�屾槸閫氳繃getCurrentPages()閫傞厤
+					this.$emit('input', index);
+				}
+			},
+			// 璁$畻瑙掓爣鐨剅ight鍊�
+			getOffsetRight(count, isDot) {
+				// 鐐圭被鍨嬶紝count澶т簬9(涓や綅鏁�)锛屽垎鍒缃笉鍚岀殑right鍊硷紝閬垮厤浣嶇疆澶尋
+				if(isDot) {
+					return -20;
+				} else if(count > 9) {
+					return -40;
+				} else {
+					return -30;
+				}
+			},
+			// 鑾峰彇鍑歌捣鎸夐挳澶栧眰鍏冪礌鐨刲eft鍊硷紝璁╁叾姘村钩灞呬腑
+			getMidButtonLeft() {
+				let windowWidth = this.$u.sys().windowWidth;
+				// 鐢变簬瀹夊崜涓璫ss璁$畻left: 50%鐨勭粨鏋滀笉鍑嗙‘锛屾晠鐢╦s璁$畻
+				this.midButtonLeft = (windowWidth / 2) + 'px';
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	@import "../../libs/css/style.components.scss";
+	.u-fixed-placeholder {
+		/* #ifndef APP-NVUE */
+		box-sizing: content-box;
+		/* #endif */
+	}
+
+	.u-tabbar {
+
+		&__content {
+			@include vue-flex;
+			align-items: center;
+			position: relative;
+			position: fixed;
+			bottom: 0;
+			left: 0;
+			width: 100%;
+			z-index: 998;
+			/* #ifndef APP-NVUE */
+			box-sizing: content-box;
+			/* #endif */
+
+			&__circle__border {
+				border-radius: 100%;
+				width: 110rpx;
+				height: 110rpx;
+				top: -48rpx;
+				position: absolute;
+				z-index: 4;
+				background-color: #ffffff;
+				// 鐢变簬瀹夊崜鐨勬棤鑳斤紝瀵艰嚧鍙湁3涓猼abbar item鏃讹紝姝ss璁$畻鏂瑰紡鏈夎宸�
+				// 鏁呬娇鐢╦s璁$畻鐨勫舰寮忔潵瀹氫綅锛屾澶勪笉娉ㄩ噴锛屾槸鍥犱负js璁$畻鏈夊欢鍚庯紝閬垮厤鍑虹幇浣嶇疆闂姩
+				left: 50%;
+				transform: translateX(-50%);
+
+				&:after {
+					border-radius: 100px;
+				}
+			}
+
+			&__item {
+				flex: 1;
+				justify-content: center;
+				height: 100%;
+				padding: 12rpx 0;
+				@include vue-flex;
+				flex-direction: column;
+				align-items: center;
+				position: relative;
+
+				&__button {
+					position: absolute;
+					top: 14rpx;
+					left: 50%;
+					transform: translateX(-50%);
+				}
+
+				&__text {
+					color: $u-content-color;
+					font-size: 26rpx;
+					line-height: 28rpx;
+					position: absolute;
+					bottom: 14rpx;
+					left: 50%;
+					transform: translateX(-50%);
+					width: 100%;
+					text-align: center;
+				}
+			}
+
+			&__circle {
+				position: relative;
+				@include vue-flex;
+				flex-direction: column;
+				justify-content: space-between;
+				z-index: 10;
+				/* #ifndef APP-NVUE */
+				height: calc(100% - 1px);
+				/* #endif */
+
+				&__button {
+					width: 90rpx;
+					height: 90rpx;
+					border-radius: 100%;
+					@include vue-flex;
+					justify-content: center;
+					align-items: center;
+					position: absolute;
+					background-color: #ffffff;
+					top: -40rpx;
+					left: 50%;
+					z-index: 6;
+					transform: translateX(-50%);
+				}
+			}
+		}
+	}
+</style>

--
Gitblit v1.9.3