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

diff --git a/uview-ui/components/u-form-item/u-form-item.vue b/uview-ui/components/u-form-item/u-form-item.vue
new file mode 100644
index 0000000..d6b8c8b
--- /dev/null
+++ b/uview-ui/components/u-form-item/u-form-item.vue
@@ -0,0 +1,431 @@
+<template>
+	<view class="u-form-item" :class="{'u-border-bottom': elBorderBottom, 'u-form-item__border-bottom--error': validateState === 'error' && showError('border-bottom')}">
+		<view class="u-form-item__body" :style="{
+			flexDirection: elLabelPosition == 'left' ? 'row' : 'column'
+		}">
+			<!-- 寰俊灏忕▼搴忎腑锛屽皢涓�涓弬鏁拌缃┖瀛楃涓诧紝缁撴灉浼氬彉鎴愬瓧绗︿覆"true" -->
+			<view class="u-form-item--left" :style="{
+				width: uLabelWidth,
+				flex: `0 0 ${uLabelWidth}`,
+				marginBottom: elLabelPosition == 'left' ? 0 : '10rpx',
+			}">
+				<!-- 涓轰簡鍧楀榻� -->
+				<view class="u-form-item--left__content" v-if="required || leftIcon || label">
+					<!-- nvue涓嶆敮鎸佷吉鍏冪礌before -->
+					<text v-if="required" class="u-form-item--left__content--required">*</text>
+					<view class="u-form-item--left__content__icon" v-if="leftIcon">
+						<u-icon :name="leftIcon" :custom-style="leftIconStyle"></u-icon>
+					</view>
+					<view class="u-form-item--left__content__label" :style="[elLabelStyle, {
+						'justify-content': elLabelAlign == 'left' ? 'flex-start' : elLabelAlign == 'center' ? 'center' : 'flex-end'
+					}]">
+						{{label}}
+					</view>
+				</view>
+			</view>
+			<view class="u-form-item--right u-flex">
+				<view class="u-form-item--right__content">
+					<view class="u-form-item--right__content__slot ">
+						<slot />
+					</view>
+					<view class="u-form-item--right__content__icon u-flex" v-if="$slots.right || rightIcon">
+						<u-icon :custom-style="rightIconStyle" v-if="rightIcon" :name="rightIcon"></u-icon>
+						<slot name="right" />
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="u-form-item__message" v-if="validateState === 'error' && showError('message')" :style="{
+			paddingLeft: elLabelPosition == 'left' ? $u.addUnit(elLabelWidth) : '0',
+		}">{{validateMessage}}</view>
+	</view>
+</template>
+
+<script>
+	import Emitter from '../../libs/util/emitter.js';
+	import schema from '../../libs/util/async-validator';
+	// 鍘婚櫎璀﹀憡淇℃伅
+	schema.warning = function() {};
+
+	/**
+	 * form-item 琛ㄥ崟item
+	 * @description 姝ょ粍浠朵竴鑸敤浜庤〃鍗曞満鏅紝鍙互閰嶇疆Input杈撳叆妗嗭紝Select寮瑰嚭妗嗭紝杩涜琛ㄥ崟楠岃瘉绛夈��
+	 * @tutorial http://uviewui.com/components/form.html
+	 * @property {String} label 宸︿晶鎻愮ず鏂囧瓧
+	 * @property {Object} prop 琛ㄥ崟鍩焟odel瀵硅薄鐨勫睘鎬у悕锛屽湪浣跨敤 validate銆乺esetFields 鏂规硶鐨勬儏鍐典笅锛岃灞炴�ф槸蹇呭~鐨�
+	 * @property {Boolean} border-bottom 鏄惁鏄剧ず琛ㄥ崟鍩熺殑涓嬪垝绾胯竟妗�
+	 * @property {String} label-position 琛ㄥ崟鍩熸彁绀烘枃瀛楃殑浣嶇疆锛宭eft-宸︿晶锛宼op-涓婃柟
+	 * @property {String Number} label-width 鎻愮ず鏂囧瓧鐨勫搴︼紝鍗曚綅rpx锛堥粯璁�90锛�
+	 * @property {Object} label-style lable鐨勬牱寮忥紝瀵硅薄褰㈠紡
+	 * @property {String} label-align lable鐨勫榻愭柟寮�
+	 * @property {String} right-icon 鍙充晶鑷畾涔夊瓧浣撳浘鏍�(闄恥View鍐呯疆鍥炬爣)鎴栧浘鐗囧湴鍧�
+	 * @property {String} left-icon 宸︿晶鑷畾涔夊瓧浣撳浘鏍�(闄恥View鍐呯疆鍥炬爣)鎴栧浘鐗囧湴鍧�
+	 * @property {Object} left-icon-style 宸︿晶鍥炬爣鐨勬牱寮忥紝瀵硅薄褰㈠紡
+	 * @property {Object} right-icon-style 鍙充晶鍥炬爣鐨勬牱寮忥紝瀵硅薄褰㈠紡
+	 * @property {Boolean} required 鏄惁鏄剧ず宸﹁竟鐨�"*"鍙凤紝杩欓噷浠呰捣灞曠ず浣滅敤锛屽闇�鏍¢獙蹇呭~锛岃閫氳繃rules閰嶇疆蹇呭~瑙勫垯(榛樿false)
+	 * @example <u-form-item label="濮撳悕"><u-input v-model="form.name" /></u-form-item>
+	 */
+
+	export default {
+		name: 'u-form-item',
+		mixins: [Emitter],
+		inject: {
+			uForm: {
+				default () {
+					return null
+				}
+			}
+		},
+		props: {
+			// input鐨刲abel鎻愮ず璇�
+			label: {
+				type: String,
+				default: ''
+			},
+			// 缁戝畾鐨勫��
+			prop: {
+				type: String,
+				default: ''
+			},
+			// 鏄惁鏄剧ず琛ㄥ崟鍩熺殑涓嬪垝绾胯竟妗�
+			borderBottom: {
+				type: [String, Boolean],
+				default: ''
+			},
+			// label鐨勪綅缃紝left-宸﹁竟锛宼op-涓婅竟
+			labelPosition: {
+				type: String,
+				default: ''
+			},
+			// label鐨勫搴︼紝鍗曚綅rpx
+			labelWidth: {
+				type: [String, Number],
+				default: ''
+			},
+			// lable鐨勬牱寮忥紝瀵硅薄褰㈠紡
+			labelStyle: {
+				type: Object,
+				default () {
+					return {}
+				}
+			},
+			// lable瀛椾綋鐨勫榻愭柟寮�
+			labelAlign: {
+				type: String,
+				default: ''
+			},
+			// 鍙充晶鍥炬爣
+			rightIcon: {
+				type: String,
+				default: ''
+			},
+			// 宸︿晶鍥炬爣
+			leftIcon: {
+				type: String,
+				default: ''
+			},
+			// 宸︿晶鍥炬爣鐨勬牱寮�
+			leftIconStyle: {
+				type: Object,
+				default () {
+					return {}
+				}
+			},
+			// 宸︿晶鍥炬爣鐨勬牱寮�
+			rightIconStyle: {
+				type: Object,
+				default () {
+					return {}
+				}
+			},
+			// 鏄惁鏄剧ず宸﹁竟鐨勫繀濉槦鍙凤紝鍙綔鏄剧ず鐢紝鍏蜂綋鏍¢獙蹇呭~鐨勯�昏緫锛岃鍦╮ules涓厤缃�
+			required: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				initialValue: '', // 瀛樺偍鐨勯粯璁ゅ��
+				// isRequired: false, // 鏄惁蹇呭~锛岀敱浜庝汉鎬у寲鑰冭檻锛屽繀濉�"*"鍙烽�氳繃props鐨剅equired閰嶇疆锛屼笉鍐嶉�氳繃rules鐨勮鍒欒嚜鍔ㄧ敓鎴�
+				validateState: '', // 鏄惁鏍¢獙鎴愬姛
+				validateMessage: '', // 鏍¢獙澶辫触鐨勬彁绀鸿
+				// 鏈夐敊璇椂鐨勬彁绀烘柟寮忥紝message-鎻愮ず淇℃伅锛宐order-濡傛灉input璁剧疆浜嗚竟妗嗭紝鍙樻垚鍛堢孩鑹诧紝
+				errorType: ['message'],
+				fieldValue: '', // 鑾峰彇褰撳墠瀛愮粍浠秈nput鐨勮緭鍏ョ殑鍊�
+				// 鐖剁粍浠剁殑鍙傛暟锛屽湪computed璁$畻涓紝鏃犳硶寰楃煡this.parent鍙戠敓鍙樺寲锛屾晠灏嗙埗缁勪欢鐨勫弬鏁板�硷紝鏀惧埌data涓�
+				parentData: {
+					borderBottom: true,
+					labelWidth: 90,
+					labelPosition: 'left',
+					labelStyle: {},
+					labelAlign: 'left',
+				}
+			};
+		},
+		watch: {
+			validateState(val) {
+				this.broadcastInputError();
+			},
+			// 鐩戝惉u-form缁勪欢鐨別rrorType鐨勫彉鍖�
+			"uForm.errorType"(val) {
+				this.errorType = val;
+				this.broadcastInputError();
+			},
+		},
+		computed: {
+			// 璁$畻鍚庣殑label瀹藉害锛岀敱浜庨渶瑕佸涓垽鏂紝鏁呮斁鍒癱omputed涓�
+			uLabelWidth() {
+				// 濡傛灉鐢ㄦ埛璁剧疆label涓虹┖瀛楃涓�(寰俊灏忕▼搴忕┖瀛楃涓叉渶缁堜細鍙樻垚瀛楃涓茬殑'true')锛屾剰鍛崇潃瑕佸皢label鐨勪綅缃搴﹁缃负auto
+				return this.elLabelPosition == 'left' ? (this.label === 'true' || this.label === '' ? 'auto' : this.$u.addUnit(this
+					.elLabelWidth)) : '100%';
+			},
+			showError() {
+				return type => {
+					// 濡傛灉errorType鏁扮粍涓惈鏈塶one锛屾垨鑰卼oast鎻愮ず绫诲瀷
+					if (this.errorType.indexOf('none') >= 0) return false;
+					else if (this.errorType.indexOf(type) >= 0) return true;
+					else return false;
+				}
+			},
+			// label鐨勫搴�
+			elLabelWidth() {
+				// label榛樿瀹藉害涓�90锛屼紭鍏堜娇鐢ㄦ湰缁勪欢鐨勫�硷紝濡傛灉娌℃湁(濡傛灉璁剧疆涓�0锛屼篃绠楁槸閰嶇疆浜嗗�硷紝渚濈劧璧锋晥)锛屽垯鐢╱-form鐨勫��
+				return (this.labelWidth != 0 || this.labelWidth != '') ? this.labelWidth : (this.parentData.labelWidth ? this.parentData
+					.labelWidth :
+					90);
+			},
+			// label鐨勬牱寮�
+			elLabelStyle() {
+				return Object.keys(this.labelStyle).length ? this.labelStyle : (this.parentData.labelStyle ? this.parentData.labelStyle :
+					{});
+			},
+			// label鐨勪綅缃紝宸︿晶鎴栬�呬笂鏂�
+			elLabelPosition() {
+				return this.labelPosition ? this.labelPosition : (this.parentData.labelPosition ? this.parentData.labelPosition :
+					'left');
+			},
+			// label鐨勫榻愭柟寮�
+			elLabelAlign() {
+				return this.labelAlign ? this.labelAlign : (this.parentData.labelAlign ? this.parentData.labelAlign : 'left');
+			},
+			// label鐨勪笅鍒掔嚎
+			elBorderBottom() {
+				// 瀛愮粍浠剁殑borderBottom榛樿涓虹┖瀛楃涓诧紝濡傛灉涓嶇瓑浜庣┖瀛楃涓诧紝鎰忓懗鐫�瀛愮粍浠惰缃簡鍊硷紝浼樺厛浣跨敤瀛愮粍浠剁殑鍊�
+				return this.borderBottom !== '' ? this.borderBottom : this.parentData.borderBottom ? this.parentData.borderBottom :
+					true;
+			}
+		},
+		methods: {
+			broadcastInputError() {
+				// 瀛愮粍浠跺彂鍑轰簨浠讹紝绗笁涓弬鏁颁负true鎴栬�協alse锛宼rue浠h〃鏈夐敊璇�
+				this.broadcast('u-input', 'on-form-item-error', this.validateState === 'error' && this.showError('border'));
+			},
+			// 鍒ゆ柇鏄惁闇�瑕乺equired鏍¢獙
+			setRules() {
+				let that = this;
+				// 鐢变簬浜烘�у寲鑰冭檻锛屽繀濉�"*"鍙烽�氳繃props鐨剅equired閰嶇疆锛屼笉鍐嶉�氳繃rules鐨勮鍒欒嚜鍔ㄧ敓鎴�
+				// 浠庣埗缁勪欢u-form鎷垮埌褰撳墠u-form-item闇�瑕侀獙璇� 鐨勮鍒�
+				// let rules = this.getRules();
+				// if (rules.length) {
+				// 	this.isRequired = rules.some(rule => {
+				// 		// 濡傛灉鏈夊繀濉」锛屽氨杩斿洖锛屾病鏈夌殑璇濓紝灏辨槸undefined
+				// 		return rule.required;
+				// 	});
+				// }
+
+				// blur浜嬩欢
+				this.$on('on-form-blur', that.onFieldBlur);
+				// change浜嬩欢
+				this.$on('on-form-change', that.onFieldChange);
+			},
+
+			// 浠巙-form鐨剅ules灞炴�т腑锛屽彇鍑哄綋鍓島-form-item鐨勬牎楠岃鍒�
+			getRules() {
+				// 鐖剁粍浠剁殑鎵�鏈夎鍒�
+				let rules = this.parent.rules;
+				rules = rules ? rules[this.prop] : [];
+				// 淇濊瘉杩斿洖鐨勬槸涓�涓暟缁勫舰寮�
+				return [].concat(rules || []);
+			},
+
+			// blur浜嬩欢鏃惰繘琛岃〃鍗曟牎楠�
+			onFieldBlur() {
+				this.validation('blur');
+			},
+
+			// change浜嬩欢杩涜琛ㄥ崟鏍¢獙
+			onFieldChange() {
+				this.validation('change');
+			},
+
+			// 杩囨护鍑虹鍚堣姹傜殑rule瑙勫垯
+			getFilteredRule(triggerType = '') {
+				let rules = this.getRules();
+				// 鏁翠綋楠岃瘉琛ㄥ崟鏃讹紝triggerType涓虹┖瀛楃涓诧紝姝ゆ椂杩斿洖鎵�鏈夎鍒欒繘琛岄獙璇�
+				if (!triggerType) return rules;
+				// 鍘嗛亶鍒ゆ柇瑙勫垯鏄惁鏈夊搴旂殑浜嬩欢锛屾瘮濡俠lur锛宑hange瑙﹀彂绛夌殑浜嬩欢
+				// 浣跨敤indexOf鍒ゆ柇锛屾槸鍥犱负鏌愪簺鏃跺�欒缃殑楠岃瘉瑙勫垯鐨則rigger灞炴�у彲鑳戒负澶氫釜锛屾瘮濡俒'blur','change']
+				// 鏌愪簺鍦烘櫙鍙兘鐨勫垽鏂鍒欙紝鍙兘涓嶅瓨鍦╰rigger灞炴�э紝鏁呭厛鍒ゆ柇鏄惁瀛樺湪姝ゅ睘鎬�
+				return rules.filter(res => res.trigger && res.trigger.indexOf(triggerType) !== -1);
+			},
+
+			// 鏍¢獙鏁版嵁
+			validation(trigger, callback = () => {}) {
+				// 妫�楠屼箣闂达紝鍏堣幏鍙栭渶瑕佹牎楠岀殑鍊�
+				this.fieldValue = this.parent.model[this.prop];
+				// blur鍜宑hange鏄惁鏈夊綋鍓嶆柟寮忕殑鏍¢獙瑙勫垯
+				let rules = this.getFilteredRule(trigger);
+				// 鍒ゆ柇鏄惁鏈夐獙璇佽鍒欙紝濡傛灉娌℃湁瑙勫垯锛屼篃璋冪敤鍥炶皟鏂规硶锛屽惁鍒欑埗缁勪欢u-form浼氬洜涓�
+				// 瀵筩ount鍙橀噺鐨勭粺璁¢敊璇�屾棤娉曡繘鍏ヤ笂涓�灞傜殑鍥炶皟
+				if (!rules || rules.length === 0) {
+					return callback('');
+				}
+				// 璁剧疆褰撳墠鐨勮濉紝鏍囪瘑涓烘牎楠屼腑
+				this.validateState = 'validating';
+				// 璋冪敤async-validator鐨勬柟娉�
+				let validator = new schema({
+					[this.prop]: rules
+				});
+				validator.validate({
+					[this.prop]: this.fieldValue
+				}, {
+					firstFields: true
+				}, (errors, fields) => {
+					// 璁板綍鐘舵�佸拰鎶ラ敊淇℃伅
+					this.validateState = !errors ? 'success' : 'error';
+					this.validateMessage = errors ? errors[0].message : '';
+					// 璋冪敤鍥炶皟鏂规硶
+					callback(this.validateMessage);
+				});
+			},
+
+			// 娓呯┖褰撳墠鐨剈-form-item
+			resetField() {
+				this.parent.model[this.prop] = this.initialValue;
+				// 璁剧疆涓篳success`鐘舵�侊紝鍙槸涓轰簡娓呯┖閿欒鏍囪
+				this.validateState = 'success';
+			}
+		},
+
+		// 缁勪欢鍒涘缓瀹屾垚鏃讹紝灏嗗綋鍓嶅疄渚嬩繚瀛樺埌u-form涓�
+		mounted() {
+			// 鏀粯瀹濄�佸ご鏉″皬绋嬪簭涓嶆敮鎸乸rovide/inject锛屾墍浠ヤ娇鐢ㄨ繖涓柟娉曡幏鍙栨暣涓埗缁勪欢锛屽湪created瀹氫箟锛岄伩鍏嶅惊鐜簲鐢�
+			this.parent = this.$u.$parent.call(this, 'u-form');
+			if (this.parent) {
+				// 鍘嗛亶parentData涓殑灞炴�э紝灏唒arent涓殑鍚屽悕灞炴�ц祴鍊肩粰parentData
+				Object.keys(this.parentData).map(key => {
+					this.parentData[key] = this.parent[key];
+				});
+				// 濡傛灉娌℃湁浼犲叆prop锛屾垨鑰卽Form涓虹┖(濡傛灉u-form-input鍗曠嫭浣跨敤锛屽氨涓嶄細鏈塽Form娉ㄥ叆)锛屽氨涓嶈繘琛屾牎楠�
+				if (this.prop) {
+					// 灏嗘湰瀹炰緥娣诲姞鍒扮埗缁勪欢涓�
+					this.parent.fields.push(this);
+					this.errorType = this.parent.errorType;
+					// 璁剧疆鍒濆鍊�
+					this.initialValue = this.fieldValue;
+					// 娣诲姞琛ㄥ崟鏍¢獙锛岃繖閲屽繀椤昏鍐欏湪$nextTick涓紝鍥犱负u-form鐨剅ules鏄�氳繃ref鎵嬪姩浼犲叆鐨�
+					// 涓嶅湪$nextTick涓殑璇濓紝鍙兘浼氶�犳垚鎵ц姝ゅ浠g爜鏃讹紝鐖剁粍浠惰繕娌¢�氳繃ref鎶婅鍒欑粰u-form锛屽鑷磋鍒欎负绌�
+					this.$nextTick(() => {
+						this.setRules();
+					})
+				}
+			}
+		},
+
+		// 缁勪欢閿�姣佸墠锛屽皢瀹炰緥浠巙-form鐨勭紦瀛樹腑绉婚櫎
+		beforeDestroy() {
+			// 濡傛灉褰撳墠娌℃湁prop鐨勮瘽琛ㄧず褰撳墠涓嶈杩涜鍒犻櫎锛堝洜涓烘病鏈夋敞鍏ワ級
+			if (this.parent && this.prop) {
+				this.parent.fields.map((item, index) => {
+					if (item === this) this.parent.fields.splice(index, 1);
+				})
+			}
+		},
+	};
+</script>
+
+<style lang="scss" scoped>
+	@import "../../libs/css/style.components.scss";
+
+	.u-form-item {
+		@include vue-flex;
+		// align-items: flex-start;
+		padding: 20rpx 0;
+		font-size: 28rpx;
+		color: $u-main-color;
+		box-sizing: border-box;
+		line-height: $u-form-item-height;
+		flex-direction: column;
+
+		&__border-bottom--error:after {
+			border-color: $u-type-error;
+		}
+
+		&__body {
+			@include vue-flex;
+		}
+
+		&--left {
+			@include vue-flex;
+			align-items: center;
+
+			&__content {
+				position: relative;
+				@include vue-flex;
+				align-items: center;
+				padding-right: 10rpx;
+				flex: 1;
+
+				&__icon {
+					margin-right: 8rpx;
+				}
+
+				&--required {
+					position: absolute;
+					left: -16rpx;
+					vertical-align: middle;
+					color: $u-type-error;
+					padding-top: 6rpx;
+				}
+
+				&__label {
+					@include vue-flex;
+					align-items: center;
+					flex: 1;
+				}
+			}
+		}
+
+		&--right {
+			flex: 1;
+
+			&__content {
+				@include vue-flex;
+				align-items: center;
+				flex: 1;
+
+				&__slot {
+					flex: 1;
+					/* #ifndef MP */
+					@include vue-flex;
+					align-items: center;
+					/* #endif */
+				}
+
+				&__icon {
+					margin-left: 10rpx;
+					color: $u-light-color;
+					font-size: 30rpx;
+				}
+			}
+		}
+
+		&__message {
+			font-size: 24rpx;
+			line-height: 24rpx;
+			color: $u-type-error;
+			margin-top: 12rpx;
+		}
+	}
+</style>

--
Gitblit v1.9.3