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

diff --git a/uview-ui/components/u-input/u-input.vue b/uview-ui/components/u-input/u-input.vue
new file mode 100644
index 0000000..f2aea72
--- /dev/null
+++ b/uview-ui/components/u-input/u-input.vue
@@ -0,0 +1,387 @@
+<template>
+	<view
+		class="u-input"
+		:class="{
+			'u-input--border': border,
+			'u-input--error': validateState
+		}"
+		:style="{
+			padding: `0 ${border ? 20 : 0}rpx`,
+			borderColor: borderColor,
+			textAlign: inputAlign
+		}"
+		@tap.stop="inputClick"
+	>
+		<textarea
+			v-if="type == 'textarea'"
+			class="u-input__input u-input__textarea"
+			:style="[getStyle]"
+			:value="defaultValue"
+			:placeholder="placeholder"
+			:placeholderStyle="placeholderStyle"
+			:disabled="disabled"
+			:maxlength="inputMaxlength"
+			:fixed="fixed"
+			:focus="focus"
+			:autoHeight="autoHeight"
+			:selection-end="uSelectionEnd"
+			:selection-start="uSelectionStart"
+			:cursor-spacing="getCursorSpacing"
+			:show-confirm-bar="showConfirmbar"
+			@input="handleInput"
+			@blur="handleBlur"
+			@focus="onFocus"
+			@confirm="onConfirm"
+		/>
+		<input
+			v-else
+			class="u-input__input"
+			:type="type == 'password' ? 'text' : type"
+			:style="[getStyle]"
+			:value="defaultValue"
+			:password="type == 'password' && !showPassword"
+			:placeholder="placeholder"
+			:placeholderStyle="placeholderStyle"
+			:disabled="disabled || type === 'select'"
+			:maxlength="inputMaxlength"
+			:focus="focus"
+			:confirmType="confirmType"
+			:cursor-spacing="getCursorSpacing"
+			:selection-end="uSelectionEnd"
+			:selection-start="uSelectionStart"
+			:show-confirm-bar="showConfirmbar"
+			@focus="onFocus"
+			@blur="handleBlur"
+			@input="handleInput"
+			@confirm="onConfirm"
+		/>
+		<view class="u-input__right-icon u-flex">
+			<view class="u-input__right-icon__clear u-input__right-icon__item" @tap="onClear" v-if="clearable && value != '' && focused">
+				<u-icon size="32" name="close-circle-fill" color="#c0c4cc"/>
+			</view>
+			<view class="u-input__right-icon__clear u-input__right-icon__item" v-if="passwordIcon && type == 'password'">
+				<u-icon size="32" :name="!showPassword ? 'eye' : 'eye-fill'" color="#c0c4cc" @click="showPassword = !showPassword"/>
+			</view>
+			<view class="u-input__right-icon--select u-input__right-icon__item" v-if="type == 'select'" :class="{
+				'u-input__right-icon--select--reverse': selectOpen
+			}">
+				<u-icon name="arrow-down-fill" size="26" color="#c0c4cc"></u-icon>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+import Emitter from '../../libs/util/emitter.js';
+
+/**
+ * input 杈撳叆妗�
+ * @description 姝ょ粍浠朵负涓�涓緭鍏ユ锛岄粯璁ゆ病鏈夎竟妗嗗拰鏍峰紡锛屾槸涓撻棬涓洪厤鍚堣〃鍗曠粍浠秛-form鑰岃璁$殑锛屽埄鐢ㄥ畠鍙互蹇�熷疄鐜拌〃鍗曢獙璇侊紝杈撳叆鍐呭锛屼笅鎷夐�夋嫨绛夊姛鑳姐��
+ * @tutorial http://uviewui.com/components/input.html
+ * @property {String} type 妯″紡閫夋嫨锛岃瀹樼綉璇存槑
+ * @property {Boolean} clearable 鏄惁鏄剧ず鍙充晶鐨勬竻闄ゅ浘鏍�(榛樿true)
+ * @property {} v-model 鐢ㄤ簬鍙屽悜缁戝畾杈撳叆妗嗙殑鍊�
+ * @property {String} input-align 杈撳叆妗嗘枃瀛楃殑瀵归綈鏂瑰紡(榛樿left)
+ * @property {String} placeholder placeholder鏄剧ず鍊�(榛樿 '璇疯緭鍏ュ唴瀹�')
+ * @property {Boolean} disabled 鏄惁绂佺敤杈撳叆妗�(榛樿false)
+ * @property {String Number} maxlength 杈撳叆妗嗙殑鏈�澶у彲杈撳叆闀垮害(榛樿140)
+ * @property {String Number} selection-start 鍏夋爣璧峰浣嶇疆锛岃嚜鍔ㄨ仛鐒︽椂鏈夋晥锛岄渶涓巗election-end鎼厤浣跨敤锛堥粯璁�-1锛�
+ * @property {String Number} maxlength 鍏夋爣缁撴潫浣嶇疆锛岃嚜鍔ㄨ仛鐒︽椂鏈夋晥锛岄渶涓巗election-start鎼厤浣跨敤锛堥粯璁�-1锛�
+ * @property {String Number} cursor-spacing 鎸囧畾鍏夋爣涓庨敭鐩樼殑璺濈锛屽崟浣峱x(榛樿0)
+ * @property {String} placeholderStyle placeholder鐨勬牱寮忥紝瀛楃涓插舰寮忥紝濡�"color: red;"(榛樿 "color: #c0c4cc;")
+ * @property {String} confirm-type 璁剧疆閿洏鍙充笅瑙掓寜閽殑鏂囧瓧锛屼粎鍦╰ype涓簍ext鏃剁敓鏁�(榛樿done)
+ * @property {Object} custom-style 鑷畾涔夎緭鍏ユ鐨勬牱寮忥紝瀵硅薄褰㈠紡
+ * @property {Boolean} focus 鏄惁鑷姩鑾峰緱鐒︾偣(榛樿false)
+ * @property {Boolean} fixed 濡傛灉type涓簍extarea锛屼笖鍦ㄤ竴涓�"position:fixed"鐨勫尯鍩燂紝闇�瑕佹寚鏄庝负true(榛樿false)
+ * @property {Boolean} password-icon type涓簆assword鏃讹紝鏄惁鏄剧ず鍙充晶鐨勫瘑鐮佹煡鐪嬪浘鏍�(榛樿true)
+ * @property {Boolean} border 鏄惁鏄剧ず杈规(榛樿false)
+ * @property {String} border-color 杈撳叆妗嗙殑杈规棰滆壊(榛樿#dcdfe6)
+ * @property {Boolean} auto-height 鏄惁鑷姩澧為珮杈撳叆鍖哄煙锛宼ype涓簍extarea鏃舵湁鏁�(榛樿true)
+ * @property {String Number} height 楂樺害锛屽崟浣峳px(text绫诲瀷鏃朵负70锛宼extarea鏃朵负100)
+ * @example <u-input v-model="value" :type="type" :border="border" />
+ */
+export default {
+	name: 'u-input',
+	mixins: [Emitter],
+	props: {
+		value: {
+			type: [String, Number],
+			default: ''
+		},
+		// 杈撳叆妗嗙殑绫诲瀷锛宼extarea锛宼ext锛宯umber
+		type: {
+			type: String,
+			default: 'text'
+		},
+		inputAlign: {
+			type: String,
+			default: 'left'
+		},
+		placeholder: {
+			type: String,
+			default: '璇疯緭鍏ュ唴瀹�'
+		},
+		disabled: {
+			type: Boolean,
+			default: false
+		},
+		maxlength: {
+			type: [Number, String],
+			default: 140
+		},
+		placeholderStyle: {
+			type: String,
+			default: 'color: #c0c4cc;'
+		},
+		confirmType: {
+			type: String,
+			default: 'done'
+		},
+		// 杈撳叆妗嗙殑鑷畾涔夋牱寮�
+		customStyle: {
+			type: Object,
+			default() {
+				return {};
+			}
+		},
+		// 濡傛灉 textarea 鏄湪涓�涓� position:fixed 鐨勫尯鍩燂紝闇�瑕佹樉绀烘寚瀹氬睘鎬� fixed 涓� true
+		fixed: {
+			type: Boolean,
+			default: false
+		},
+		// 鏄惁鑷姩鑾峰緱鐒︾偣
+		focus: {
+			type: Boolean,
+			default: false
+		},
+		// 瀵嗙爜绫诲瀷鏃讹紝鏄惁鏄剧ず鍙充晶鐨勫瘑鐮佸浘鏍�
+		passwordIcon: {
+			type: Boolean,
+			default: true
+		},
+		// input|textarea鏄惁鏄剧ず杈规
+		border: {
+			type: Boolean,
+			default: false
+		},
+		// 杈撳叆妗嗙殑杈规棰滆壊
+		borderColor: {
+			type: String,
+			default: '#dcdfe6'
+		},
+		autoHeight: {
+			type: Boolean,
+			default: true
+		},
+		// type=select鏃讹紝鏃嬭浆鍙充晶鐨勫浘鏍囷紝鏍囪瘑褰撳墠澶勪簬鎵撳紑杩樻槸鍏抽棴select鐨勭姸鎬�
+		// open-鎵撳紑锛宑lose-鍏抽棴
+		selectOpen: {
+			type: Boolean,
+			default: false
+		},
+		// 楂樺害锛屽崟浣峳px
+		height: {
+			type: [Number, String],
+			default: ''
+		},
+		// 鏄惁鍙竻绌�
+		clearable: {
+			type: Boolean,
+			default: true
+		},
+		// 鎸囧畾鍏夋爣涓庨敭鐩樼殑璺濈锛屽崟浣� px
+		cursorSpacing: {
+			type: [Number, String],
+			default: 0
+		},
+		// 鍏夋爣璧峰浣嶇疆锛岃嚜鍔ㄨ仛鐒︽椂鏈夋晥锛岄渶涓巗election-end鎼厤浣跨敤
+		selectionStart: {
+			type: [Number, String],
+			default: -1
+		},
+		// 鍏夋爣缁撴潫浣嶇疆锛岃嚜鍔ㄨ仛鐒︽椂鏈夋晥锛岄渶涓巗election-start鎼厤浣跨敤
+		selectionEnd: {
+			type: [Number, String],
+			default: -1
+		},
+		// 鏄惁鑷姩鍘婚櫎涓ょ鐨勭┖鏍�
+		trim: {
+			type: Boolean,
+			default: true
+		},
+		// 鏄惁鏄剧ず閿洏涓婃柟甯︽湁鈥濆畬鎴愨�滄寜閽偅涓�鏍�
+		showConfirmbar:{
+			type:Boolean,
+			default:true
+		}
+	},
+	data() {
+		return {
+			defaultValue: this.value,
+			inputHeight: 70, // input鐨勯珮搴�
+			textareaHeight: 100, // textarea鐨勯珮搴�
+			validateState: false, // 褰撳墠input鐨勯獙璇佺姸鎬侊紝鐢ㄤ簬閿欒鏃讹紝杈规鏄惁鏀逛负绾㈣壊
+			focused: false, // 褰撳墠鏄惁澶勪簬鑾峰緱鐒︾偣鐨勭姸鎬�
+			showPassword: false, // 鏄惁棰勮瀵嗙爜
+			lastValue: '', // 鐢ㄤ簬澶存潯灏忕▼搴忥紝鍒ゆ柇@input涓紝鍓嶅悗鐨勫�兼槸鍚﹀彂鐢熶簡鍙樺寲锛屽洜涓哄ご鏉′腑鏂囦笅锛屾寜涓嬮敭娌℃湁杈撳叆鍐呭锛屼篃浼氳Е鍙慇input鏃堕棿
+		};
+	},
+	watch: {
+		value(nVal, oVal) {
+			this.defaultValue = nVal;
+			// 褰撳�煎彂鐢熷彉鍖栵紝涓斾负select绫诲瀷鏃�(姝ゆ椂input琚缃负disabled锛屼笉浼氳Е鍙慇input浜嬩欢)锛屾ā鎷熻Е鍙慇input浜嬩欢
+			if(nVal != oVal && this.type == 'select') this.handleInput({
+				detail: {
+					value: nVal
+				}
+			})
+		},
+	},
+	computed: {
+		// 鍥犱负uniapp鐨刬nput缁勪欢鐨刴axlength缁勪欢蹇呴』瑕佹暟鍊硷紝杩欓噷杞负鏁板�硷紝缁欑敤鎴峰彲浠ヤ紶鍏ュ瓧绗︿覆鏁板��
+		inputMaxlength() {
+			return Number(this.maxlength);
+		},
+		getStyle() {
+			let style = {};
+			// 濡傛灉娌℃湁鑷畾涔夐珮搴︼紝灏辨牴鎹畉ype涓篿nput杩樻槸textare鏉ュ垎閰嶄竴涓粯璁ょ殑楂樺害
+			style.minHeight = this.height ? this.height + 'rpx' : this.type == 'textarea' ?
+				this.textareaHeight + 'rpx' : this.inputHeight + 'rpx';
+			style = Object.assign(style, this.customStyle);
+			return style;
+		},
+		//
+		getCursorSpacing() {
+			return Number(this.cursorSpacing);
+		},
+		// 鍏夋爣璧峰浣嶇疆
+		uSelectionStart() {
+			return String(this.selectionStart);
+		},
+		// 鍏夋爣缁撴潫浣嶇疆
+		uSelectionEnd() {
+			return String(this.selectionEnd);
+		}
+	},
+	created() {
+		// 鐩戝惉u-form-item鍙戝嚭鐨勯敊璇簨浠讹紝灏嗚緭鍏ユ杈规鍙樼孩鑹�
+		this.$on('on-form-item-error', this.onFormItemError);
+	},
+	methods: {
+		/**
+		 * change 浜嬩欢
+		 * @param event
+		 */
+		handleInput(event) {
+			let value = event.detail.value;
+			// 鍒ゆ柇鏄惁鍘婚櫎绌烘牸
+			if(this.trim) value = this.$u.trim(value);
+			// vue 鍘熺敓鐨勬柟娉� return 鍑哄幓
+			this.$emit('input', value);
+			// 褰撳墠model 璧嬪��
+			this.defaultValue = value;
+			// 杩囦竴涓敓鍛藉懆鏈熷啀鍙戦�佷簨浠剁粰u-form-item锛屽惁鍒檛his.$emit('input')鏇存柊浜嗙埗缁勪欢鐨勫�硷紝浣嗘槸寰俊灏忕▼搴忎笂
+			// 灏氭湭鏇存柊鍒皍-form-item锛屽鑷磋幏鍙栫殑鍊间负绌猴紝浠庤�屾牎楠屾贩璁�
+			// 杩欓噷涓嶈兘寤舵椂鏃堕棿澶煭锛屾垨鑰呬娇鐢╰his.$nextTick锛屽惁鍒欏湪澶存潯涓婏紝浼氶�犳垚娣蜂贡
+			setTimeout(() => {
+				// 澶存潯灏忕▼搴忕敱浜庤嚜韬玝ug锛屽鑷翠腑鏂囦笅锛屾瘡鎸変笅涓�涓敭(灏氭湭瀹屾垚杈撳叆)锛岄兘浼氳Е鍙戜竴娆input锛屽鑷撮敊璇紝杩欓噷杩涜鍒ゆ柇澶勭悊
+				// #ifdef MP-TOUTIAO
+				if(this.$u.trim(value) == this.lastValue) return ;
+				this.lastValue = value;
+				// #endif
+				// 灏嗗綋鍓嶇殑鍊煎彂閫佸埌 u-form-item 杩涜鏍¢獙
+				this.dispatch('u-form-item', 'on-form-change', value);
+			}, 40)
+		},
+		/**
+		 * blur 浜嬩欢
+		 * @param event
+		 */
+		handleBlur(event) {
+			// 鏈�寮�濮嬩娇鐢ㄧ殑鏄洃鍚浘鏍嘆touchstart浜嬩欢锛岃嚜浠巋x2.8.4鍚庯紝姝ゆ柟娉曞湪寰俊灏忕▼搴忓嚭閿�
+			// 杩欓噷鏀逛负鐩戝惉鐐瑰嚮浜嬩欢锛屾墜鐐瑰嚮娓呴櫎鍥炬爣鏃讹紝鍚屾椂涔熷彂鐢熶簡@blur浜嬩欢锛屽鑷村浘鏍囨秷澶辫�屾棤娉曠偣鍑伙紝杩欓噷鍋氫竴涓欢鏃�
+			setTimeout(() => {
+				this.focused = false;
+			}, 100)
+			// vue 鍘熺敓鐨勬柟娉� return 鍑哄幓
+			this.$emit('blur', event.detail.value);
+			setTimeout(() => {
+				// 澶存潯灏忕▼搴忕敱浜庤嚜韬玝ug锛屽鑷翠腑鏂囦笅锛屾瘡鎸変笅涓�涓敭(灏氭湭瀹屾垚杈撳叆)锛岄兘浼氳Е鍙戜竴娆input锛屽鑷撮敊璇紝杩欓噷杩涜鍒ゆ柇澶勭悊
+				// #ifdef MP-TOUTIAO
+				if(this.$u.trim(value) == this.lastValue) return ;
+				this.lastValue = value;
+				// #endif
+				// 灏嗗綋鍓嶇殑鍊煎彂閫佸埌 u-form-item 杩涜鏍¢獙
+				this.dispatch('u-form-item', 'on-form-blur', event.detail.value);
+			}, 40)
+		},
+		onFormItemError(status) {
+			this.validateState = status;
+		},
+		onFocus(event) {
+			this.focused = true;
+			this.$emit('focus');
+		},
+		onConfirm(e) {
+			this.$emit('confirm', e.detail.value);
+		},
+		onClear(event) {
+			this.$emit('input', '');
+		},
+		inputClick() {
+			this.$emit('click');
+		}
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+@import "../../libs/css/style.components.scss";
+
+.u-input {
+	position: relative;
+	flex: 1;
+	@include vue-flex;
+
+	&__input {
+		//height: $u-form-item-height;
+		font-size: 28rpx;
+		color: $u-main-color;
+		flex: 1;
+	}
+
+	&__textarea {
+		width: auto;
+		font-size: 28rpx;
+		color: $u-main-color;
+		padding: 10rpx 0;
+		line-height: normal;
+		flex: 1;
+	}
+
+	&--border {
+		border-radius: 6rpx;
+		border-radius: 4px;
+		border: 1px solid $u-form-item-border-color;
+	}
+
+	&--error {
+		border-color: $u-type-error!important;
+	}
+
+	&__right-icon {
+
+		&__item {
+			margin-left: 10rpx;
+		}
+
+		&--select {
+			transition: transform .4s;
+
+			&--reverse {
+				transform: rotate(-180deg);
+			}
+		}
+	}
+}
+</style>

--
Gitblit v1.9.3