¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="u-form"> |
| | | <slot /> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | import props from "./props.js"; |
| | | import Schema from "../../libs/util/async-validator"; |
| | | // å»é¤è¦åä¿¡æ¯ |
| | | Schema.warning = function() {}; |
| | | /** |
| | | * Form 表å |
| | | * @description æ¤ç»ä»¶ä¸è¬ç¨äºè¡¨ååºæ¯ï¼å¯ä»¥é
ç½®Inputè¾å
¥æ¡ï¼Selectå¼¹åºæ¡ï¼è¿è¡è¡¨åéªè¯çã |
| | | * @tutorial https://www.uviewui.com/components/form.html |
| | | * @property {Object} model å½åformçéè¦éªè¯å段çéå |
| | | * @property {Object | Function | Array} rules éªè¯è§å |
| | | * @property {String} errorType é误çæç¤ºæ¹å¼ï¼è§ä¸æ¹è¯´æ ( é»è®¤ message ) |
| | | * @property {Boolean} borderBottom æ¯å¦æ¾ç¤ºè¡¨ååçä¸åçº¿è¾¹æ¡ ( é»è®¤ true ï¼ |
| | | * @property {String} labelPosition 表ååæç¤ºæåçä½ç½®ï¼left-左侧ï¼top-䏿¹ ( é»è®¤ 'left' ï¼ |
| | | * @property {String | Number} labelWidth æç¤ºæåç宽度ï¼åä½px ( é»è®¤ 45 ï¼ |
| | | * @property {String} labelAlign lableåä½ç坹齿¹å¼ ( é»è®¤ âleft' ï¼ |
| | | * @property {Object} labelStyle lableçæ ·å¼ï¼å¯¹è±¡å½¢å¼ |
| | | * @example <u--formlabelPosition="left" :model="model1" :rules="rules" ref="form1"></u--form> |
| | | */ |
| | | export default { |
| | | name: "u-form", |
| | | mixins: [uni.$u.mpMixin, uni.$u.mixin, props], |
| | | provide() { |
| | | return { |
| | | uForm: this, |
| | | }; |
| | | }, |
| | | data() { |
| | | return { |
| | | formRules: {}, |
| | | // è§åæ ¡éªå¨ |
| | | validator: {}, |
| | | // åå§çmodelå¿«ç
§ï¼ç¨äºresetFieldsæ¹æ³éç½®è¡¨åæ¶ä½¿ç¨ |
| | | originalModel: null, |
| | | }; |
| | | }, |
| | | watch: { |
| | | // çå¬è§åçåå |
| | | rules: { |
| | | immediate: true, |
| | | handler(n) { |
| | | this.setRules(n); |
| | | }, |
| | | }, |
| | | // çå¬å±æ§çååï¼éç¥åç»ä»¶u-form-iteméæ°è·åä¿¡æ¯ |
| | | propsChange(n) { |
| | | if (this.children?.length) { |
| | | this.children.map((child) => { |
| | | // 夿åç»ä»¶(u-form-item)妿æupdateParentDataæ¹æ³çè¯ï¼å°±å°±æ§è¡(æ§è¡çç»ææ¯åç»ä»¶éæ°ä»ç¶ç»ä»¶æåäºææ°çå¼) |
| | | typeof child.updateParentData == "function" && |
| | | child.updateParentData(); |
| | | }); |
| | | } |
| | | }, |
| | | // çå¬modelçåå§å¼ä½ä¸ºé置表åçå¿«ç
§ |
| | | model: { |
| | | immediate: true, |
| | | handler(n) { |
| | | if (!this.originalModel) { |
| | | this.originalModel = uni.$u.deepClone(n); |
| | | } |
| | | }, |
| | | }, |
| | | }, |
| | | computed: { |
| | | propsChange() { |
| | | return [ |
| | | this.errorType, |
| | | this.borderBottom, |
| | | this.labelPosition, |
| | | this.labelWidth, |
| | | this.labelAlign, |
| | | this.labelStyle, |
| | | ]; |
| | | }, |
| | | }, |
| | | created() { |
| | | // åå¨å½åformä¸çææu-form-itemçå®ä¾ |
| | | // ä¸è½å®ä¹å¨dataä¸ï¼å¦å微信å°ç¨åºä¼é æå¾ªç¯å¼ç¨èæ¥é |
| | | this.children = []; |
| | | }, |
| | | methods: { |
| | | // æå¨è®¾ç½®æ ¡éªçè§åï¼å¦æè§å䏿彿°çè¯ï¼å¾®ä¿¡å°ç¨åºä¸ä¼è¿æ»¤æï¼æä»¥åªè½æå¨è°ç¨è®¾ç½®è§å |
| | | setRules(rules) { |
| | | // 夿æ¯å¦æè§å |
| | | if (Object.keys(rules).length === 0) return; |
| | | if (process.env.NODE_ENV === 'development' && Object.keys(this.model).length === 0) { |
| | | uni.$u.error('设置rulesï¼modelå¿
须设置ï¼å¦æå·²ç»è®¾ç½®ï¼è¯·å·æ°é¡µé¢ã'); |
| | | return; |
| | | }; |
| | | this.formRules = rules; |
| | | // éæ°å°è§åèµäºValidator |
| | | this.validator = new Schema(rules); |
| | | }, |
| | | // æ¸
空ææu-form-itemç»ä»¶çå
å®¹ï¼æ¬è´¨ä¸æ¯è°ç¨äºu-form-itemç»ä»¶ä¸çresetField()æ¹æ³ |
| | | resetFields() { |
| | | this.resetModel(); |
| | | }, |
| | | // éç½®model为åå§å¼çå¿«ç
§ |
| | | resetModel(obj) { |
| | | // åéææu-form-itemï¼æ ¹æ®å
¶prop屿§ï¼è¿åmodelçåå§å¿«ç
§ |
| | | this.children.map((child) => { |
| | | const prop = child?.prop; |
| | | const value = uni.$u.getProperty(this.originalModel, prop); |
| | | uni.$u.setProperty(this.model, prop, value); |
| | | }); |
| | | }, |
| | | // æ¸
ç©ºæ ¡éªç»æ |
| | | clearValidate(props) { |
| | | props = [].concat(props); |
| | | this.children.map((child) => { |
| | | // 妿u-form-itemçpropå¨propsæ°ç»ä¸ï¼åæ¸
é¤å¯¹åºçæ ¡éªç»æä¿¡æ¯ |
| | | if (props[0] === undefined || props.includes(child.prop)) { |
| | | child.message = null; |
| | | } |
| | | }); |
| | | }, |
| | | // 对é¨å表ååæ®µè¿è¡æ ¡éª |
| | | async validateField(value, callback, event = null) { |
| | | // $nextTickæ¯å¿
é¡»çï¼å¦åmodelçåæ´ï¼å¯è½ä¼å»¶åäºæ¤æ¹æ³çæ§è¡ |
| | | this.$nextTick(() => { |
| | | // æ ¡éªé误信æ¯ï¼è¿åç»åè°æ¹æ³ï¼ç¨äºåæ¾ææform-itemçéè¯¯ä¿¡æ¯ |
| | | const errorsRes = []; |
| | | // å¦æä¸ºå符串ï¼è½¬ä¸ºæ°ç» |
| | | value = [].concat(value); |
| | | // åéchildrenææåform-item |
| | | this.children.map((child) => { |
| | | // ç¨äºåæ¾form-itemçéè¯¯ä¿¡æ¯ |
| | | const childErrors = []; |
| | | if (value.includes(child.prop)) { |
| | | // è·å对åºç屿§ï¼éè¿ç±»ä¼¼'a.b.c'çå½¢å¼ |
| | | const propertyVal = uni.$u.getProperty( |
| | | this.model, |
| | | child.prop |
| | | ); |
| | | // 屿§é¾æ°ç» |
| | | const propertyChain = child.prop.split("."); |
| | | const propertyName = |
| | | propertyChain[propertyChain.length - 1]; |
| | | |
| | | const rule = this.formRules[child.prop]; |
| | | // 妿ä¸åå¨å¯¹åºçè§åï¼ç´æ¥è¿åï¼å¦åæ ¡éªå¨ä¼æ¥é |
| | | if (!rule) return; |
| | | // ruleè§åå¯ä¸ºæ°ç»å½¢å¼ï¼ä¹å¯ä¸ºå¯¹è±¡å½¢å¼ï¼æ¤å¤æ¼æ¥æä¸ºæ°ç» |
| | | const rules = [].concat(rule); |
| | | |
| | | // 对rulesæ°ç»è¿è¡æ ¡éª |
| | | for (let i = 0; i < rules.length; i++) { |
| | | const ruleItem = rules[i]; |
| | | // å°u-form-itemç触åå¨è½¬ä¸ºæ°ç»å½¢å¼ |
| | | const trigger = [].concat(ruleItem?.trigger); |
| | | // å¦ææ¯æä¼ å
¥è§¦åäºä»¶ï¼ä½æ¯æ¤form-itemå´æ²¡æé
ç½®æ¤è§¦åå¨çè¯ï¼ä¸æ§è¡æ ¡éªæä½ |
| | | if (event && !trigger.includes(event)) continue; |
| | | // å®ä¾åæ ¡éªå¯¹è±¡ï¼ä¼ å
¥æé è§å |
| | | const validator = new Schema({ |
| | | [propertyName]: ruleItem, |
| | | }); |
| | | validator.validate({ |
| | | [propertyName]: propertyVal, |
| | | }, |
| | | (errors, fields) => { |
| | | if (uni.$u.test.array(errors)) { |
| | | errorsRes.push(...errors); |
| | | childErrors.push(...errors); |
| | | } |
| | | child.message = |
| | | childErrors[0]?.message ?? null; |
| | | } |
| | | ); |
| | | } |
| | | } |
| | | }); |
| | | // æ§è¡åè°å½æ° |
| | | typeof callback === "function" && callback(errorsRes); |
| | | }); |
| | | }, |
| | | // æ ¡éªå
¨é¨æ°æ® |
| | | validate(callback) { |
| | | // å¼åç¯å¢ææç¤ºï¼ç产ç¯å¢ä¸ä¼æç¤º |
| | | if (process.env.NODE_ENV === 'development' && Object.keys(this.formRules).length === 0) { |
| | | uni.$u.error('æªè®¾ç½®rulesï¼è¯·çææ¡£è¯´æï¼å¦æå·²ç»è®¾ç½®ï¼è¯·å·æ°é¡µé¢ã'); |
| | | return; |
| | | } |
| | | return new Promise((resolve, reject) => { |
| | | // $nextTickæ¯å¿
é¡»çï¼å¦åmodelçåæ´ï¼å¯è½ä¼å»¶åäºvalidateæ¹æ³ |
| | | this.$nextTick(() => { |
| | | // è·åææform-itemçpropï¼äº¤ç»validateFieldæ¹æ³è¿è¡æ ¡éª |
| | | const formItemProps = this.children.map( |
| | | (item) => item.prop |
| | | ); |
| | | this.validateField(formItemProps, (errors) => { |
| | | if(errors.length) { |
| | | // 妿é误æç¤ºæ¹å¼ä¸ºtoastï¼åè¿è¡æç¤º |
| | | this.errorType === 'toast' && uni.$u.toast(errors[0].message) |
| | | reject(errors) |
| | | } else { |
| | | resolve(true) |
| | | } |
| | | }); |
| | | }); |
| | | }); |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | </style> |