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-number-box/u-number-box.vue |  363 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 363 insertions(+), 0 deletions(-)

diff --git a/uview-ui/components/u-number-box/u-number-box.vue b/uview-ui/components/u-number-box/u-number-box.vue
new file mode 100644
index 0000000..54a679e
--- /dev/null
+++ b/uview-ui/components/u-number-box/u-number-box.vue
@@ -0,0 +1,363 @@
+<template>
+	<view class="u-numberbox">
+		<view class="u-icon-minus" @touchstart.stop.prevent="btnTouchStart('minus')" @touchend.stop.prevent="clearTimer" :class="{ 'u-icon-disabled': disabled || inputVal <= min }"
+		    :style="{
+				background: bgColor,
+				height: inputHeight + 'rpx',
+				color: color
+			}">
+			<u-icon name="minus" :size="size"></u-icon>
+		</view>
+		<input :disabled="disabledInput || disabled" :cursor-spacing="getCursorSpacing" :class="{ 'u-input-disabled': disabled }"
+		    v-model="inputVal" class="u-number-input" @blur="onBlur" @focus="onFocus"
+		    type="number" :style="{
+				color: color,
+				fontSize: size + 'rpx',
+				background: bgColor,
+				height: inputHeight + 'rpx',
+				width: inputWidth + 'rpx'
+			}" />
+		<view class="u-icon-plus" @touchstart.stop.prevent="btnTouchStart('plus')" @touchend.stop.prevent="clearTimer" :class="{ 'u-icon-disabled': disabled || inputVal >= max }"
+		    :style="{
+				background: bgColor,
+				height: inputHeight + 'rpx',
+				color: color
+			}">
+			<u-icon name="plus" :size="size"></u-icon>
+		</view>
+	</view>
+</template>
+
+<script>
+	/**
+	 * numberBox 姝ヨ繘鍣�
+	 * @description 璇ョ粍浠朵竴鑸敤浜庡晢鍩庤喘鐗╅�夋嫨鐗╁搧鏁伴噺鐨勫満鏅�傛敞鎰忥細璇ヨ緭鍏ユ鍙兘杈撳叆澶т簬鎴栫瓑浜�0鐨勬暣鏁帮紝涓嶆敮鎸佸皬鏁拌緭鍏�
+	 * @tutorial https://www.uviewui.com/components/numberBox.html
+	 * @property {Number} value 杈撳叆妗嗗垵濮嬪�硷紙榛樿1锛�
+	 * @property {String} bg-color 杈撳叆妗嗗拰鎸夐挳鐨勮儗鏅鑹诧紙榛樿#F2F3F5锛�
+	 * @property {Number} min 鐢ㄦ埛鍙緭鍏ョ殑鏈�灏忓�硷紙榛樿0锛�
+	 * @property {Number} max 鐢ㄦ埛鍙緭鍏ョ殑鏈�澶у�硷紙榛樿99999锛�
+	 * @property {Number} step 姝ラ暱锛屾瘡娆″姞鎴栧噺鐨勫�硷紙榛樿1锛�
+	 * @property {Boolean} disabled 鏄惁绂佺敤鎿嶄綔锛岀鐢ㄥ悗鏃犳硶鍔犲噺鎴栨墜鍔ㄤ慨鏀硅緭鍏ユ鐨勫�硷紙榛樿false锛�
+	 * @property {Boolean} disabled-input 鏄惁绂佹杈撳叆妗嗘墜鍔ㄨ緭鍏ュ�硷紙榛樿false锛�
+	 * @property {Boolean} positive-integer 鏄惁鍙兘杈撳叆姝f暣鏁帮紙榛樿true锛�
+	 * @property {String | Number} size 杈撳叆妗嗘枃瀛楀拰鎸夐挳瀛椾綋澶у皬锛屽崟浣峳px锛堥粯璁�26锛�
+	 * @property {String} color 杈撳叆妗嗘枃瀛楀拰鍔犲噺鎸夐挳鍥炬爣鐨勯鑹诧紙榛樿#323233锛�
+	 * @property {String | Number} input-width 杈撳叆妗嗗搴︼紝鍗曚綅rpx锛堥粯璁�80锛�
+	 * @property {String | Number} input-height 杈撳叆妗嗗拰鎸夐挳鐨勯珮搴︼紝鍗曚綅rpx锛堥粯璁�50锛�
+	 * @property {String | Number} index 浜嬩欢鍥炶皟鏃剁敤浠ュ尯鍒嗗綋鍓嶅彂鐢熷彉鍖栫殑鏄摢涓緭鍏ユ
+	 * @property {Boolean} long-press 鏄惁寮�鍚暱鎸夎繛缁�掑鎴栭�掑噺(榛樿true)
+	 * @property {String | Number} press-time 寮�鍚暱鎸夎Е鍙戝悗锛屾瘡瑙﹀彂涓�娆¢渶瑕佸涔咃紝鍗曚綅ms(榛樿250)
+	 * @property {String | Number} cursor-spacing 鎸囧畾鍏夋爣浜庨敭鐩樼殑璺濈锛岄伩鍏嶉敭鐩橀伄鎸¤緭鍏ユ锛屽崟浣峳px锛堥粯璁�200锛�
+	 * @event {Function} change 杈撳叆妗嗗唴瀹瑰彂鐢熷彉鍖栨椂瑙﹀彂锛屽璞″舰寮�
+	 * @event {Function} blur 杈撳叆妗嗗け鍘荤劍鐐规椂瑙﹀彂锛屽璞″舰寮�
+	 * @event {Function} minus 鐐瑰嚮鍑忓皯鎸夐挳鏃惰Е鍙�(鎸夐挳鍙偣鍑绘儏鍐典笅)锛屽璞″舰寮�
+	 * @event {Function} plus 鐐瑰嚮澧炲姞鎸夐挳鏃惰Е鍙�(鎸夐挳鍙偣鍑绘儏鍐典笅)锛屽璞″舰寮�
+	 * @example <u-number-box :min="1" :max="100"></u-number-box>
+	 */
+	export default {
+		name: "u-number-box",
+		props: {
+			// 棰勬樉绀虹殑鏁板瓧
+			value: {
+				type: Number,
+				default: 1
+			},
+			// 鑳屾櫙棰滆壊
+			bgColor: {
+				type: String,
+				default: '#F2F3F5'
+			},
+			// 鏈�灏忓��
+			min: {
+				type: Number,
+				default: 0
+			},
+			// 鏈�澶у��
+			max: {
+				type: Number,
+				default: 99999
+			},
+			// 姝ヨ繘鍊硷紝姣忔鍔犳垨鍑忕殑鍊�
+			step: {
+				type: Number,
+				default: 1
+			},
+			// 鏄惁绂佺敤鍔犲噺鎿嶄綔
+			disabled: {
+				type: Boolean,
+				default: false
+			},
+			// input鐨勫瓧浣撳ぇ灏忥紝鍗曚綅rpx
+			size: {
+				type: [Number, String],
+				default: 26
+			},
+			// 鍔犲噺鍥炬爣鐨勯鑹�
+			color: {
+				type: String,
+				default: '#323233'
+			},
+			// input瀹藉害锛屽崟浣峳px
+			inputWidth: {
+				type: [Number, String],
+				default: 80
+			},
+			// input楂樺害锛屽崟浣峳px
+			inputHeight: {
+				type: [Number, String],
+				default: 50
+			},
+			// index绱㈠紩锛岀敤浜庡垪琛ㄤ腑浣跨敤锛岃鐢ㄦ埛鐭ラ亾鏄摢涓猲umberbox鍙戠敓浜嗗彉鍖栵紝涓�鑸娇鐢╢or寰幆鍑烘潵鐨刬ndex鍊煎嵆鍙�
+			index: {
+				type: [Number, String],
+				default: ''
+			},
+			// 鏄惁绂佺敤杈撳叆妗嗭紝涓巇isabled浣滅敤浜庤緭鍏ユ鏃讹紝涓篛R鐨勫叧绯伙紝鍗虫兂瑕佺鐢ㄨ緭鍏ユ锛屽張鍙互鍔犲噺鐨勮瘽
+			// 璁剧疆disabled涓篺alse锛宒isabledInput涓簍rue鍗冲彲
+			disabledInput: {
+				type: Boolean,
+				default: false
+			},
+			// 杈撳叆妗嗕簬閿洏涔嬮棿鐨勮窛绂�
+			cursorSpacing: {
+				type: [Number, String],
+				default: 100
+			},
+			// 鏄惁寮�鍚暱鎸夎繛缁�掑鎴栭�掑噺
+			longPress: {
+				type: Boolean,
+				default: true
+			},
+			// 寮�鍚暱鎸夎Е鍙戝悗锛屾瘡瑙﹀彂涓�娆¢渶瑕佸涔�
+			pressTime: {
+				type: [Number, String],
+				default: 250
+			},
+			// 鏄惁鍙兘杈撳叆澶т簬鎴栫瓑浜�0鐨勬暣鏁�(姝f暣鏁�)
+			positiveInteger: {
+				type: Boolean,
+				default: true
+			}
+		},
+		watch: {
+			value(v1, v2) {
+				// 鍙湁value鐨勬敼鍙樻槸鏉ヨ嚜澶栭儴鐨勬椂鍊欙紝鎵嶅幓鍚屾inputVal鐨勫�硷紝鍚﹀垯浼氶�犳垚寰幆閿欒
+				if(!this.changeFromInner) {
+					this.inputVal = v1;
+					// 鍥犱负inputVal鍙樺寲鍚庯紝浼氳Е鍙憈his.handleChange()锛屽湪鍏朵腑changeFromInner浼氬啀娆¤璁剧疆涓簍rue锛�
+					// 閫犳垚澶栭潰淇敼鍊硷紝涔熷鑷磋璁や负鏄唴閮ㄤ慨鏀圭殑娣蜂贡锛岃繖閲岃繘琛宼his.$nextTick寤舵椂锛屼繚璇佸湪杩愯鍛ㄦ湡鐨勬渶鍚庡
+					// 灏哻hangeFromInner璁剧疆涓篺alse
+					this.$nextTick(function(){
+						this.changeFromInner = false;
+					})
+				}
+			},
+			inputVal(v1, v2) {
+				// 涓轰簡璁╃敤鎴疯兘澶熷垹闄ゆ墍鏈夎緭鍏ュ�硷紝閲嶆柊杈撳叆鍐呭锛屽垹闄ゆ墍鏈夊�煎悗锛屽唴瀹逛负绌哄瓧绗︿覆
+				if (v1 == '') return;
+				let value = 0;
+				// 棣栧厛鍒ゆ柇鏄惁鏁板�硷紝骞朵笖鍦╩in鍜宮ax涔嬮棿锛屽鏋滀笉鏄紝浣跨敤鍘熸潵鍊�
+				let tmp = this.$u.test.number(v1);
+				if (tmp && v1 >= this.min && v1 <= this.max) value = v1;
+				else value = v2;
+				// 鍒ゆ柇鏄惁鍙兘杈撳叆澶т簬绛変簬0鐨勬暣鏁�
+				if(this.positiveInteger) {
+					// 灏忎簬0锛屾垨鑰呭甫鏈夊皬鏁扮偣锛�
+					if(v1 < 0 || String(v1).indexOf('.') !== -1) {
+						value = v2;
+						// 鍙屽悜缁戝畾input鐨勫�硷紝蹇呴』瑕佷娇鐢�$nextTick淇敼鏄剧ず鐨勫��
+						this.$nextTick(() => {
+							this.inputVal = v2;
+						})
+					}
+				}
+				// 鍙戝嚭change浜嬩欢
+				this.handleChange(value, 'change');
+			}
+		},
+		data() {
+			return {
+				inputVal: 1, // 杈撳叆妗嗕腑鐨勫�硷紝涓嶈兘鐩存帴浣跨敤props涓殑value锛屽洜涓哄簲璇ユ敼鍙榩rops鐨勭姸鎬�
+				timer: null, // 鐢ㄤ綔闀挎寜鐨勫畾鏃跺櫒
+				changeFromInner: false, // 鍊煎彂鐢熷彉鍖栵紝鏄潵鑷唴閮ㄨ繕鏄閮�
+				innerChangeTimer: null, // 鍐呴儴瀹氭椂鍣�
+			};
+		},
+		created() {
+			this.inputVal = Number(this.value);
+		},
+		computed: {
+			getCursorSpacing() {
+				// 鍏堝皢鍊艰浆涓簆x鍗曚綅锛屽啀杞负鏁板��
+				return Number(uni.upx2px(this.cursorSpacing));
+			}
+		},
+		methods: {
+			// 鐐瑰嚮閫�鏍奸敭
+			btnTouchStart(callback) {
+				// 鍏堟墽琛屼竴閬嶆柟娉曪紝鍚﹀垯浼氶�犳垚鏉惧紑鎵嬫椂锛屽氨鎵ц浜哻learTimer锛屽鑷存棤娉曞疄鐜板姛鑳�
+				this[callback]();
+				// 濡傛灉娌″紑鍚暱鎸夊姛鑳斤紝鐩存帴杩斿洖
+				if (!this.longPress) return;
+				clearInterval(this.timer); //鍐嶆娓呯┖瀹氭椂鍣紝闃叉閲嶅娉ㄥ唽瀹氭椂鍣�
+				this.timer = null;
+				this.timer = setInterval(() => {
+					// 鎵ц鍔犳垨鍑忓嚱鏁�
+					this[callback]();
+				}, this.pressTime);
+			},
+			clearTimer() {
+				this.$nextTick(() => {
+					clearInterval(this.timer);
+					this.timer = null;
+				})
+			},
+			minus() {
+				this.computeVal('minus');
+			},
+			plus() {
+				this.computeVal('plus');
+			},
+			// 涓轰簡淇濊瘉灏忔暟鐩稿姞鍑忓嚭鐜扮簿搴︽孩鍑虹殑闂
+			calcPlus(num1, num2) {
+				let baseNum, baseNum1, baseNum2;
+				try {
+					baseNum1 = num1.toString().split('.')[1].length;
+				} catch (e) {
+					baseNum1 = 0;
+				}
+				try {
+					baseNum2 = num2.toString().split('.')[1].length;
+				} catch (e) {
+					baseNum2 = 0;
+				}
+				baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
+				let precision = baseNum1 >= baseNum2 ? baseNum1 : baseNum2; //绮惧害
+				return ((num1 * baseNum + num2 * baseNum) / baseNum).toFixed(precision);
+			},
+			// 涓轰簡淇濊瘉灏忔暟鐩稿姞鍑忓嚭鐜扮簿搴︽孩鍑虹殑闂
+			calcMinus(num1, num2) {
+				let baseNum, baseNum1, baseNum2;
+				try {
+					baseNum1 = num1.toString().split('.')[1].length;
+				} catch (e) {
+					baseNum1 = 0;
+				}
+				try {
+					baseNum2 = num2.toString().split('.')[1].length;
+				} catch (e) {
+					baseNum2 = 0;
+				}
+				baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
+				let precision = baseNum1 >= baseNum2 ? baseNum1 : baseNum2;
+				return ((num1 * baseNum - num2 * baseNum) / baseNum).toFixed(precision);
+			},
+			computeVal(type) {
+				uni.hideKeyboard();
+				if (this.disabled) return;
+				let value = 0;
+				// 鍑�
+				if (type === 'minus') {
+					value = this.calcMinus(this.inputVal, this.step);
+				} else if (type === 'plus') {
+					value = this.calcPlus(this.inputVal, this.step);
+				}
+				// 鍒ゆ柇鏄惁灏忎簬鏈�灏忓�煎拰澶т簬鏈�澶у��
+				if (value < this.min || value > this.max) {
+					return;
+				}
+				this.inputVal = value;
+				this.handleChange(value, type);
+			},
+			// 澶勭悊鐢ㄦ埛鎵嬪姩杈撳叆鐨勬儏鍐�
+			onBlur(event) {
+				let val = 0;
+				let value = event.detail.value;
+				// 濡傛灉涓洪潪0-9鏁板瓧缁勬垚锛屾垨鑰呭叾绗竴浣嶆暟鍊间负0锛岀洿鎺ヨ鍏剁瓑浜巑in鍊�
+				// 杩欓噷涓嶇洿鎺ュ垽鏂槸鍚︽鏁存暟锛屾槸鍥犱负鐢ㄦ埛浼犻�掔殑props min鍊煎彲鑳戒负0
+				if (!/(^\d+$)/.test(value) || value[0] == 0) val = this.min;
+				val = +value;
+				if (val > this.max) {
+					val = this.max;
+				} else if (val < this.min) {
+					val = this.min;
+				}
+				this.$nextTick(() => {
+					this.inputVal = val;
+				})
+				this.handleChange(val, 'blur');
+			},
+			// 杈撳叆妗嗚幏寰楃劍鐐逛簨浠�
+			onFocus() {
+				this.$emit('focus');
+			},
+			handleChange(value, type) {
+				if (this.disabled) return;
+				// 娓呴櫎瀹氭椂鍣紝閬垮厤閫犳垚娣蜂贡
+				if(this.innerChangeTimer) {
+					clearTimeout(this.innerChangeTimer);
+					this.innerChangeTimer = null;
+				}
+				// 鍙戝嚭input浜嬩欢锛屼慨鏀归�氳繃v-model缁戝畾鐨勫�硷紝杈惧埌鍙屽悜缁戝畾鐨勬晥鏋�
+				this.changeFromInner = true;
+				// 涓�瀹氭椂闂村唴锛屾竻闄hangeFromInner鏍囪锛屽惁鍒欏唴閮ㄥ�兼敼鍙樺悗
+				// 澶栭儴閫氳繃绋嬪簭淇敼value鍊硷紝灏嗕細鏃犳晥
+				this.innerChangeTimer = setTimeout(() => {
+					this.changeFromInner = false;
+				}, 150);
+				this.$emit('input', Number(value));
+				this.$emit(type, {
+					// 杞负Number绫诲瀷
+					value: Number(value),
+					index: this.index
+				})
+			}
+		}
+	};
+</script>
+
+<style lang="scss" scoped>
+	@import "../../libs/css/style.components.scss";
+
+	.u-numberbox {
+		display: inline-flex;
+		align-items: center;
+	}
+
+	.u-number-input {
+		position: relative;
+		text-align: center;
+		padding: 0;
+		margin: 0 6rpx;
+		@include vue-flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.u-icon-plus,
+	.u-icon-minus {
+		width: 60rpx;
+		@include vue-flex;
+		justify-content: center;
+		align-items: center;
+	}
+
+	.u-icon-plus {
+		border-radius: 0 8rpx 8rpx 0;
+	}
+
+	.u-icon-minus {
+		border-radius: 8rpx 0 0 8rpx;
+	}
+
+	.u-icon-disabled {
+		color: #c8c9cc !important;
+		background: #f7f8fa !important;
+	}
+
+	.u-input-disabled {
+		color: #c8c9cc !important;
+		background-color: #f2f3f5 !important;
+	}
+</style>

--
Gitblit v1.9.3