@10yun/cv-mobile-ui 0.5.20 → 0.5.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/package.json +1 -1
  2. package/ui-cv/components/cv-grid-item/cv-grid-item.vue +1 -1
  3. package/uni-ui/lib/uni-badge/uni-badge.vue +150 -1
  4. package/uni-ui/lib/uni-breadcrumb/uni-breadcrumb.vue +37 -1
  5. package/uni-ui/lib/uni-breadcrumb-item/uni-breadcrumb-item.vue +83 -1
  6. package/uni-ui/lib/uni-calendar/uni-calendar-item.vue +122 -1
  7. package/uni-ui/lib/uni-calendar/uni-calendar.vue +366 -1
  8. package/uni-ui/lib/uni-card/uni-card.vue +124 -1
  9. package/uni-ui/lib/uni-col/uni-col.vue +1 -1
  10. package/uni-ui/lib/uni-collapse/uni-collapse.vue +135 -1
  11. package/uni-ui/lib/uni-collapse-item/uni-collapse-item.vue +266 -1
  12. package/uni-ui/lib/uni-combox/uni-combox.vue +1 -1
  13. package/uni-ui/lib/uni-countdown/uni-countdown.vue +239 -1
  14. package/uni-ui/lib/uni-data-checkbox/uni-data-checkbox.vue +487 -1
  15. package/uni-ui/lib/uni-data-picker/uni-data-picker.vue +530 -1
  16. package/uni-ui/lib/uni-data-pickerview/uni-data-picker.js +157 -150
  17. package/uni-ui/lib/uni-data-pickerview/uni-data-pickerview.vue +166 -1
  18. package/uni-ui/lib/uni-data-select/uni-data-select.vue +289 -1
  19. package/uni-ui/lib/uni-datetime-picker/calendar-item.vue +70 -1
  20. package/uni-ui/lib/uni-datetime-picker/calendar.vue +629 -1
  21. package/uni-ui/lib/uni-datetime-picker/time-picker.vue +741 -1
  22. package/uni-ui/lib/uni-datetime-picker/uni-datetime-picker.vue +847 -1
  23. package/uni-ui/lib/uni-drawer/uni-drawer.vue +115 -1
  24. package/uni-ui/lib/uni-easyinput/uni-easyinput.vue +515 -1
  25. package/uni-ui/lib/uni-fab/uni-fab.vue +257 -1
  26. package/uni-ui/lib/uni-fav/uni-fav.vue +123 -1
  27. package/uni-ui/lib/uni-file-picker/uni-file-picker.vue +642 -1
  28. package/uni-ui/lib/uni-file-picker/upload-file.vue +177 -1
  29. package/uni-ui/lib/uni-file-picker/upload-image.vue +176 -1
  30. package/uni-ui/lib/uni-forms/uni-forms.vue +375 -1
  31. package/uni-ui/lib/uni-forms-item/uni-forms-item.vue +429 -1
  32. package/uni-ui/lib/uni-goods-nav/uni-goods-nav.vue +129 -1
  33. package/uni-ui/lib/uni-grid/uni-grid.vue +115 -1
  34. package/uni-ui/lib/uni-grid-item/uni-grid-item.vue +78 -1
  35. package/uni-ui/lib/uni-group/uni-group.vue +85 -1
  36. package/uni-ui/lib/uni-icons/uni-icons.vue +85 -1
  37. package/uni-ui/lib/uni-indexed-list/uni-indexed-list-item.vue +68 -1
  38. package/uni-ui/lib/uni-indexed-list/uni-indexed-list.vue +294 -1
  39. package/uni-ui/lib/uni-list/uni-list.vue +81 -1
  40. package/uni-ui/lib/uni-list-ad/uni-list-ad.vue +77 -1
  41. package/uni-ui/lib/uni-list-chat/uni-list-chat.vue +294 -1
  42. package/uni-ui/lib/uni-list-item/uni-list-item.vue +346 -1
  43. package/uni-ui/lib/uni-load-more/uni-load-more.vue +172 -1
  44. package/uni-ui/lib/uni-nav-bar/uni-nav-bar.vue +205 -1
  45. package/uni-ui/lib/uni-nav-bar/uni-status-bar.vue +18 -1
  46. package/uni-ui/lib/uni-notice-bar/uni-notice-bar.vue +331 -1
  47. package/uni-ui/lib/uni-number-box/uni-number-box.vue +166 -1
  48. package/uni-ui/lib/uni-pagination/uni-pagination.vue +323 -1
  49. package/uni-ui/lib/uni-popup/uni-popup.vue +1 -1
  50. package/uni-ui/lib/uni-popup-dialog/uni-popup-dialog.vue +173 -1
  51. package/uni-ui/lib/uni-popup-message/uni-popup-message.vue +74 -1
  52. package/uni-ui/lib/uni-popup-share/uni-popup-share.vue +106 -1
  53. package/uni-ui/lib/uni-rate/uni-rate.vue +322 -1
  54. package/uni-ui/lib/uni-row/uni-row.vue +1 -1
  55. package/uni-ui/lib/uni-search-bar/uni-search-bar.vue +236 -1
  56. package/uni-ui/lib/uni-section/uni-section.vue +109 -1
  57. package/uni-ui/lib/uni-segmented-control/uni-segmented-control.vue +103 -1
  58. package/uni-ui/lib/uni-status-bar/uni-status-bar.vue +1 -1
  59. package/uni-ui/lib/uni-steps/uni-steps.vue +120 -1
  60. package/uni-ui/lib/uni-swipe-action-item/uni-swipe-action-item.vue +226 -3
  61. package/uni-ui/lib/uni-swiper-dot/uni-swiper-dot.vue +167 -1
  62. package/uni-ui/lib/uni-table/uni-table.vue +297 -1
  63. package/uni-ui/lib/uni-tag/uni-tag.vue +100 -1
  64. package/uni-ui/lib/uni-td/uni-td.vue +78 -1
  65. package/uni-ui/lib/uni-th/filter-dropdown.vue +1 -1
  66. package/uni-ui/lib/uni-th/uni-th.vue +224 -1
  67. package/uni-ui/lib/uni-thead/uni-thead.vue +77 -1
  68. package/uni-ui/lib/uni-tr/table-checkbox.vue +79 -1
  69. package/uni-ui/lib/uni-tr/uni-tr.vue +135 -1
@@ -1 +1,429 @@
1
- <template>
2
1
  <view
3
2
  class="uni-forms-item"
4
3
  :class="[
5
4
  'is-direction-' + localLabelPos,
6
5
  border ? 'uni-forms-item--border' : '',
7
6
  border && isFirstBorder ? 'is-first-border' : ''
8
7
  ]"
9
8
  >
10
9
  <slot name="label">
11
10
  <view
12
11
  class="uni-forms-item__label"
13
12
  :class="{ 'no-label': !label && !required }"
14
13
  :style="{ width: localLabelWidth, justifyContent: localLabelAlign }"
15
14
  >
16
15
  <text v-if="required" class="is-required">*</text>
17
16
  <text>{{ label }}</text>
18
17
  </view>
19
18
  </slot>
20
19
  <!-- #ifndef APP-NVUE -->
21
20
  <view class="uni-forms-item__content">
22
21
  <slot></slot>
23
22
  <view class="uni-forms-item__error" :class="{ 'msg--active': msg }">
24
23
  <text>{{ msg }}</text>
25
24
  </view>
26
25
  </view>
27
26
  <!-- #endif -->
28
27
  <!-- #ifdef APP-NVUE -->
29
28
  <view class="uni-forms-item__nuve-content">
30
29
  <view class="uni-forms-item__content">
31
30
  <slot></slot>
32
31
  </view>
33
32
  <view class="uni-forms-item__error" :class="{ 'msg--active': msg }">
34
33
  <text class="error-text">{{ msg }}</text>
35
34
  </view>
36
35
  </view>
37
36
  <!-- #endif -->
38
37
  </view>
39
38
  * uni-fomrs-item 表单子组件
40
39
  * @description uni-fomrs-item 表单子组件,提供了基础布局已经校验能力
41
40
  * @tutorial https://ext.dcloud.net.cn/plugin?id=2773
42
41
  * @property {Boolean} required 是否必填,左边显示红色"*"号
43
42
  * @property {String } label 输入框左边的文字提示
44
43
  * @property {Number } labelWidth label的宽度,单位px(默认65)
45
44
  * @property {String } labelAlign = [left|center|right] label的文字对齐方式(默认left)
46
45
  * @value left label 左侧显示
47
46
  * @value center label 居中
48
47
  * @value right label 右侧对齐
49
48
  * @property {String } errorMessage 显示的错误提示内容,如果为空字符串或者false,则不显示错误信息
50
49
  * @property {String } name 表单域的属性名,在使用校验规则时必填
51
50
  * @property {String } leftIcon 【1.4.0废弃】label左边的图标,限 uni-ui 的图标名称
52
51
  * @property {String } iconColor 【1.4.0废弃】左边通过icon配置的图标的颜色(默认#606266)
53
52
  * @property {String} validateTrigger = [bind|submit|blur] 【1.4.0废弃】校验触发器方式 默认 submit
54
53
  * @value bind 发生变化时触发
55
54
  * @value submit 提交时触发
56
55
  * @value blur 失去焦点触发
57
56
  * @property {String } labelPosition = [top|left] 【1.4.0废弃】label的文字的位置(默认left)
58
57
  * @value top 顶部显示 label
59
58
  * @value left 左侧显示 label
60
59
  */
61
60
  name: 'uniFormsItem',
62
61
  options: {
63
62
  virtualHost: true
64
63
  },
65
64
  provide() {
66
65
  return {
67
66
  uniFormItem: this
68
67
  };
69
68
  },
70
69
  inject: {
71
70
  form: {
72
71
  from: 'uniForm',
73
72
  default: null
74
73
  }
75
74
  },
76
75
  props: {
77
76
  // 表单校验规则
78
77
  rules: {
79
78
  type: Array,
80
79
  default() {
81
80
  return null;
82
81
  }
83
82
  },
84
83
  // 表单域的属性名,在使用校验规则时必填
85
84
  name: {
86
85
  type: [String, Array],
87
86
  default: ''
88
87
  },
89
88
  required: {
90
89
  type: Boolean,
91
90
  default: false
92
91
  },
93
92
  label: {
94
93
  type: String,
95
94
  default: ''
96
95
  },
97
96
  // label的宽度 ,默认 80
98
97
  labelWidth: {
99
98
  type: [String, Number],
100
99
  default: ''
101
100
  },
102
101
  // label 居中方式,默认 left 取值 left/center/right
103
102
  labelAlign: {
104
103
  type: String,
105
104
  default: ''
106
105
  },
107
106
  // 强制显示错误信息
108
107
  errorMessage: {
109
108
  type: [String, Boolean],
110
109
  default: ''
111
110
  },
112
111
  // 1.4.0 弃用,统一使用 form 的校验时机
113
112
  // validateTrigger: {
114
113
  // type: String,
115
114
  // default: ''
116
115
  // },
117
116
  // 1.4.0 弃用,统一使用 form 的label 位置
118
117
  // labelPosition: {
119
118
  // type: String,
120
119
  // default: ''
121
120
  // },
122
121
  // 1.4.0 以下属性已经废弃,请使用 #label 插槽代替
123
122
  leftIcon: String,
124
123
  iconColor: {
125
124
  type: String,
126
125
  default: '#606266'
127
126
  }
128
127
  },
129
128
  data() {
130
129
  return {
131
130
  errMsg: '',
132
131
  userRules: null,
133
132
  localLabelAlign: 'left',
134
133
  localLabelWidth: '65px',
135
134
  localLabelPos: 'left',
136
135
  border: false,
137
136
  isFirstBorder: false
138
137
  };
139
138
  },
140
139
  computed: {
141
140
  // 处理错误信息
142
141
  msg() {
143
142
  return this.errorMessage || this.errMsg;
144
143
  }
145
144
  },
146
145
  watch: {
147
146
  // 规则发生变化通知子组件更新
148
147
  'form.formRules'(val) {
149
148
  // TODO 处理头条vue3 watch不生效的问题
150
149
  // #ifndef MP-TOUTIAO
151
150
  this.init();
152
151
  // #endif
153
152
  },
154
153
  'form.labelWidth'(val) {
155
154
  // 宽度
156
155
  this.localLabelWidth = this._labelWidthUnit(val);
157
156
  },
158
157
  'form.labelPosition'(val) {
159
158
  // 标签位置
160
159
  this.localLabelPos = this._labelPosition();
161
160
  },
162
161
  'form.labelAlign'(val) {}
163
162
  },
164
163
  created() {
165
164
  this.init(true);
166
165
  if (this.name && this.form) {
167
166
  // TODO 处理头条vue3 watch不生效的问题
168
167
  // #ifdef MP-TOUTIAO
169
168
  this.$watch('form.formRules', () => {
170
169
  this.init();
171
170
  });
172
171
  // #endif
173
172
  // 监听变化
174
173
  this.$watch(
175
174
  () => {
176
175
  const val = this.form._getDataValue(this.name, this.form.localData);
177
176
  return val;
178
177
  },
179
178
  (value, oldVal) => {
180
179
  const isEqual = this.form._isEqual(value, oldVal);
181
180
  // 简单判断前后值的变化,只有发生变化才会发生校验
182
181
  // TODO 如果 oldVal = undefined ,那么大概率是源数据里没有值导致 ,这个情况不哦校验 ,可能不严谨 ,需要在做观察
183
182
  // fix by mehaotian 暂时取消 && oldVal !== undefined ,如果formData 中不存在,可能会不校验
184
183
  if (!isEqual) {
185
184
  const val = this.itemSetValue(value);
186
185
  this.onFieldChange(val, false);
187
186
  }
188
187
  },
189
188
  {
190
189
  immediate: false
191
190
  }
192
191
  );
193
192
  }
194
193
  },
195
194
  // #ifndef VUE3
196
195
  destroyed() {
197
196
  if (this.__isUnmounted) return;
198
197
  this.unInit();
199
198
  },
200
199
  // #endif
201
200
  // #ifdef VUE3
202
201
  unmounted() {
203
202
  this.__isUnmounted = true;
204
203
  this.unInit();
205
204
  },
206
205
  // #endif
207
206
  methods: {
208
207
  /**
209
208
  * 外部调用方法
210
209
  * 设置规则 ,主要用于小程序自定义检验规则
211
210
  * @param {Array} rules 规则源数据
212
211
  */
213
212
  setRules(rules = null) {
214
213
  this.userRules = rules;
215
214
  this.init(false);
216
215
  },
217
216
  // 兼容老版本表单组件
218
217
  setValue() {
219
218
  // console.log('setValue 方法已经弃用,请使用最新版本的 uni-forms 表单组件以及其他关联组件。');
220
219
  },
221
220
  /**
222
221
  * 外部调用方法
223
222
  * 校验数据
224
223
  * @param {any} value 需要校验的数据
225
224
  * @param {boolean} 是否立即校验
226
225
  * @return {Array|null} 校验内容
227
226
  */
228
227
  async onFieldChange(value, formtrigger = true) {
229
228
  const { formData, localData, errShowType, validateCheck, validateTrigger, _isRequiredField, _realName } = this.form;
230
229
  const name = _realName(this.name);
231
230
  if (!value) {
232
231
  value = this.form.formData[name];
233
232
  }
234
233
  // fixd by mehaotian 不在校验前清空信息,解决闪屏的问题
235
234
  // this.errMsg = '';
236
235
  // fix by mehaotian 解决没有检验规则的情况下,抛出错误的问题
237
236
  const ruleLen = this.itemRules.rules && this.itemRules.rules.length;
238
237
  if (!this.validator || !ruleLen || ruleLen === 0) return;
239
238
  // 检验时机
240
239
  // let trigger = this.isTrigger(this.itemRules.validateTrigger, this.validateTrigger, validateTrigger);
241
240
  const isRequiredField = _isRequiredField(this.itemRules.rules || []);
242
241
  let result = null;
243
242
  // 只有等于 bind 时 ,才能开启时实校验
244
243
  if (validateTrigger === 'bind' || formtrigger) {
245
244
  // 校验当前表单项
246
245
  result = await this.validator.validateUpdate(
247
246
  {
248
247
  [name]: value
249
248
  },
250
249
  formData
251
250
  );
252
251
  // 判断是否必填,非必填,不填不校验,填写才校验 ,暂时只处理 undefined 和空的情况
253
252
  if (!isRequiredField && (value === undefined || value === '')) {
254
253
  result = null;
255
254
  }
256
255
  // 判断错误信息显示类型
257
256
  if (result && result.errorMessage) {
258
257
  if (errShowType === 'undertext') {
259
258
  // 获取错误信息
260
259
  this.errMsg = !result ? '' : result.errorMessage;
261
260
  }
262
261
  if (errShowType === 'toast') {
263
262
  uni.showToast({
264
263
  title: result.errorMessage || '校验错误',
265
264
  icon: 'none'
266
265
  });
267
266
  }
268
267
  if (errShowType === 'modal') {
269
268
  uni.showModal({
270
269
  title: '提示',
271
270
  content: result.errorMessage || '校验错误'
272
271
  });
273
272
  }
274
273
  } else {
275
274
  this.errMsg = '';
276
275
  }
277
276
  // 通知 form 组件更新事件
278
277
  validateCheck(result ? result : null);
279
278
  } else {
280
279
  this.errMsg = '';
281
280
  }
282
281
  return result ? result : null;
283
282
  },
284
283
  /**
285
284
  * 初始组件数据
286
285
  */
287
286
  init(type = false) {
288
287
  const { validator, formRules, childrens, formData, localData, _realName, labelWidth, _getDataValue, _setDataValue } =
289
288
  this.form || {};
290
289
  // 对齐方式
291
290
  this.localLabelAlign = this._justifyContent();
292
291
  // 宽度
293
292
  this.localLabelWidth = this._labelWidthUnit(labelWidth);
294
293
  // 标签位置
295
294
  this.localLabelPos = this._labelPosition();
296
295
  // 将需要校验的子组件加入form 队列
297
296
  this.form && type && childrens.push(this);
298
297
  if (!validator || !formRules) return;
299
298
  // 判断第一个 item
300
299
  if (!this.form.isFirstBorder) {
301
300
  this.form.isFirstBorder = true;
302
301
  this.isFirstBorder = true;
303
302
  }
304
303
  // 判断 group 里的第一个 item
305
304
  if (this.group) {
306
305
  if (!this.group.isFirstBorder) {
307
306
  this.group.isFirstBorder = true;
308
307
  this.isFirstBorder = true;
309
308
  }
310
309
  }
311
310
  this.border = this.form.border;
312
311
  // 获取子域的真实名称
313
312
  const name = _realName(this.name);
314
313
  const itemRule = this.userRules || this.rules;
315
314
  if (typeof formRules === 'object' && itemRule) {
316
315
  // 子规则替换父规则
317
316
  formRules[name] = {
318
317
  rules: itemRule
319
318
  };
320
319
  validator.updateSchema(formRules);
321
320
  }
322
321
  // 注册校验规则
323
322
  const itemRules = formRules[name] || {};
324
323
  this.itemRules = itemRules;
325
324
  // 注册校验函数
326
325
  this.validator = validator;
327
326
  // 默认值赋予
328
327
  this.itemSetValue(_getDataValue(this.name, localData));
329
328
  },
330
329
  unInit() {
331
330
  if (this.form) {
332
331
  const { childrens, formData, _realName } = this.form;
333
332
  childrens.forEach((item, index) => {
334
333
  if (item === this) {
335
334
  this.form.childrens.splice(index, 1);
336
335
  delete formData[_realName(item.name)];
337
336
  }
338
337
  });
339
338
  }
340
339
  },
341
340
  // 设置item 的值
342
341
  itemSetValue(value) {
343
342
  const name = this.form._realName(this.name);
344
343
  const rules = this.itemRules.rules || [];
345
344
  const val = this.form._getValue(name, value, rules);
346
345
  this.form._setDataValue(name, this.form.formData, val);
347
346
  return val;
348
347
  },
349
348
  /**
350
349
  * 移除该表单项的校验结果
351
350
  */
352
351
  clearValidate() {
353
352
  this.errMsg = '';
354
353
  },
355
354
  // 是否显示星号
356
355
  _isRequired() {
357
356
  // TODO 不根据规则显示 星号,考虑后续兼容
358
357
  // if (this.form) {
359
358
  // if (this.form._isRequiredField(this.itemRules.rules || []) && this.required) {
360
359
  // return true
361
360
  // }
362
361
  // return false
363
362
  // }
364
363
  return this.required;
365
364
  },
366
365
  // 处理对齐方式
367
366
  _justifyContent() {
368
367
  if (this.form) {
369
368
  const { labelAlign } = this.form;
370
369
  let labelAli = this.labelAlign ? this.labelAlign : labelAlign;
371
370
  if (labelAli === 'left') return 'flex-start';
372
371
  if (labelAli === 'center') return 'center';
373
372
  if (labelAli === 'right') return 'flex-end';
374
373
  }
375
374
  return 'flex-start';
376
375
  },
377
376
  // 处理 label宽度单位 ,继承父元素的值
378
377
  _labelWidthUnit(labelWidth) {
379
378
  // if (this.form) {
380
379
  // const {
381
380
  // labelWidth
382
381
  // } = this.form
383
382
  return this.num2px(this.labelWidth ? this.labelWidth : labelWidth || (this.label ? 65 : 'auto'));
384
383
  // }
385
384
  // return '65px'
386
385
  },
387
386
  // 处理 label 位置
388
387
  _labelPosition() {
389
388
  if (this.form) return this.form.labelPosition || 'left';
390
389
  return 'left';
391
390
  },
392
391
  /**
393
392
  * 触发时机
394
393
  * @param {Object} rule 当前规则内时机
395
394
  * @param {Object} itemRlue 当前组件时机
396
395
  * @param {Object} parentRule 父组件时机
397
396
  */
398
397
  isTrigger(rule, itemRlue, parentRule) {
399
398
  // bind submit
400
399
  if (rule === 'submit' || !rule) {
401
400
  if (rule === undefined) {
402
401
  if (itemRlue !== 'bind') {
403
402
  if (!itemRlue) {
404
403
  return parentRule === '' ? 'bind' : 'submit';
405
404
  }
406
405
  return 'submit';
407
406
  }
408
407
  return 'bind';
409
408
  }
410
409
  return 'submit';
411
410
  }
412
411
  return 'bind';
413
412
  },
414
413
  num2px(num) {
415
414
  if (typeof num === 'number') {
416
415
  return `${num}px`;
417
416
  }
418
417
  return num;
419
418
  }
420
419
  }
420
+ <template>
421
+ <view
422
+ class="uni-forms-item"
423
+ :class="[
424
+ 'is-direction-' + localLabelPos,
425
+ border ? 'uni-forms-item--border' : '',
426
+ border && isFirstBorder ? 'is-first-border' : ''
427
+ ]"
428
+ >
429
+ <slot name="label">
430
+ <view
431
+ class="uni-forms-item__label"
432
+ :class="{ 'no-label': !label && !required }"
433
+ :style="{ width: localLabelWidth, justifyContent: localLabelAlign }"
434
+ >
435
+ <text v-if="required" class="is-required">*</text>
436
+ <text>{{ label }}</text>
437
+ </view>
438
+ </slot>
439
+ <!-- #ifndef APP-NVUE -->
440
+ <view class="uni-forms-item__content">
441
+ <slot></slot>
442
+ <view class="uni-forms-item__error" :class="{ 'msg--active': msg }">
443
+ <text>{{ msg }}</text>
444
+ </view>
445
+ </view>
446
+ <!-- #endif -->
447
+ <!-- #ifdef APP-NVUE -->
448
+ <view class="uni-forms-item__nuve-content">
449
+ <view class="uni-forms-item__content">
450
+ <slot></slot>
451
+ </view>
452
+ <view class="uni-forms-item__error" :class="{ 'msg--active': msg }">
453
+ <text class="error-text">{{ msg }}</text>
454
+ </view>
455
+ </view>
456
+ <!-- #endif -->
457
+ </view>
458
+ </template>
459
+ <script>
460
+ /**
461
+ * uni-fomrs-item 表单子组件
462
+ * @description uni-fomrs-item 表单子组件,提供了基础布局已经校验能力
463
+ * @tutorial https://ext.dcloud.net.cn/plugin?id=2773
464
+ * @property {Boolean} required 是否必填,左边显示红色"*"号
465
+ * @property {String } label 输入框左边的文字提示
466
+ * @property {Number } labelWidth label的宽度,单位px(默认65)
467
+ * @property {String } labelAlign = [left|center|right] label的文字对齐方式(默认left)
468
+ * @value left label 左侧显示
469
+ * @value center label 居中
470
+ * @value right label 右侧对齐
471
+ * @property {String } errorMessage 显示的错误提示内容,如果为空字符串或者false,则不显示错误信息
472
+ * @property {String } name 表单域的属性名,在使用校验规则时必填
473
+ * @property {String } leftIcon 【1.4.0废弃】label左边的图标,限 uni-ui 的图标名称
474
+ * @property {String } iconColor 【1.4.0废弃】左边通过icon配置的图标的颜色(默认#606266)
475
+ * @property {String} validateTrigger = [bind|submit|blur] 【1.4.0废弃】校验触发器方式 默认 submit
476
+ * @value bind 发生变化时触发
477
+ * @value submit 提交时触发
478
+ * @value blur 失去焦点触发
479
+ * @property {String } labelPosition = [top|left] 【1.4.0废弃】label的文字的位置(默认left)
480
+ * @value top 顶部显示 label
481
+ * @value left 左侧显示 label
482
+ */
483
+ export default {
484
+ name: 'uniFormsItem',
485
+ options: {
486
+ virtualHost: true
487
+ },
488
+ provide() {
489
+ return {
490
+ uniFormItem: this
491
+ };
492
+ },
493
+ inject: {
494
+ form: {
495
+ from: 'uniForm',
496
+ default: null
497
+ }
498
+ },
499
+ props: {
500
+ // 表单校验规则
501
+ rules: {
502
+ type: Array,
503
+ default() {
504
+ return null;
505
+ }
506
+ },
507
+ // 表单域的属性名,在使用校验规则时必填
508
+ name: {
509
+ type: [String, Array],
510
+ default: ''
511
+ },
512
+ required: {
513
+ type: Boolean,
514
+ default: false
515
+ },
516
+ label: {
517
+ type: String,
518
+ default: ''
519
+ },
520
+ // label的宽度 ,默认 80
521
+ labelWidth: {
522
+ type: [String, Number],
523
+ default: ''
524
+ },
525
+ // label 居中方式,默认 left 取值 left/center/right
526
+ labelAlign: {
527
+ type: String,
528
+ default: ''
529
+ },
530
+ // 强制显示错误信息
531
+ errorMessage: {
532
+ type: [String, Boolean],
533
+ default: ''
534
+ },
535
+ // 1.4.0 弃用,统一使用 form 的校验时机
536
+ // validateTrigger: {
537
+ // type: String,
538
+ // default: ''
539
+ // },
540
+ // 1.4.0 弃用,统一使用 form 的label 位置
541
+ // labelPosition: {
542
+ // type: String,
543
+ // default: ''
544
+ // },
545
+ // 1.4.0 以下属性已经废弃,请使用 #label 插槽代替
546
+ leftIcon: String,
547
+ iconColor: {
548
+ type: String,
549
+ default: '#606266'
550
+ }
551
+ },
552
+ data() {
553
+ return {
554
+ errMsg: '',
555
+ userRules: null,
556
+ localLabelAlign: 'left',
557
+ localLabelWidth: '65px',
558
+ localLabelPos: 'left',
559
+ border: false,
560
+ isFirstBorder: false
561
+ };
562
+ },
563
+ computed: {
564
+ // 处理错误信息
565
+ msg() {
566
+ return this.errorMessage || this.errMsg;
567
+ }
568
+ },
569
+ watch: {
570
+ // 规则发生变化通知子组件更新
571
+ 'form.formRules'(val) {
572
+ // TODO 处理头条vue3 watch不生效的问题
573
+ // #ifndef MP-TOUTIAO
574
+ this.init();
575
+ // #endif
576
+ },
577
+ 'form.labelWidth'(val) {
578
+ // 宽度
579
+ this.localLabelWidth = this._labelWidthUnit(val);
580
+ },
581
+ 'form.labelPosition'(val) {
582
+ // 标签位置
583
+ this.localLabelPos = this._labelPosition();
584
+ },
585
+ 'form.labelAlign'(val) {}
586
+ },
587
+ created() {
588
+ this.init(true);
589
+ if (this.name && this.form) {
590
+ // TODO 处理头条vue3 watch不生效的问题
591
+ // #ifdef MP-TOUTIAO
592
+ this.$watch('form.formRules', () => {
593
+ this.init();
594
+ });
595
+ // #endif
596
+ // 监听变化
597
+ this.$watch(
598
+ () => {
599
+ const val = this.form._getDataValue(this.name, this.form.localData);
600
+ return val;
601
+ },
602
+ (value, oldVal) => {
603
+ const isEqual = this.form._isEqual(value, oldVal);
604
+ // 简单判断前后值的变化,只有发生变化才会发生校验
605
+ // TODO 如果 oldVal = undefined ,那么大概率是源数据里没有值导致 ,这个情况不哦校验 ,可能不严谨 ,需要在做观察
606
+ // fix by mehaotian 暂时取消 && oldVal !== undefined ,如果formData 中不存在,可能会不校验
607
+ if (!isEqual) {
608
+ const val = this.itemSetValue(value);
609
+ this.onFieldChange(val, false);
610
+ }
611
+ },
612
+ {
613
+ immediate: false
614
+ }
615
+ );
616
+ }
617
+ },
618
+ // #ifndef VUE3
619
+ destroyed() {
620
+ if (this.__isUnmounted) return;
621
+ this.unInit();
622
+ },
623
+ // #endif
624
+ // #ifdef VUE3
625
+ unmounted() {
626
+ this.__isUnmounted = true;
627
+ this.unInit();
628
+ },
629
+ // #endif
630
+ methods: {
631
+ /**
632
+ * 外部调用方法
633
+ * 设置规则 ,主要用于小程序自定义检验规则
634
+ * @param {Array} rules 规则源数据
635
+ */
636
+ setRules(rules = null) {
637
+ this.userRules = rules;
638
+ this.init(false);
639
+ },
640
+ // 兼容老版本表单组件
641
+ setValue() {
642
+ // console.log('setValue 方法已经弃用,请使用最新版本的 uni-forms 表单组件以及其他关联组件。');
643
+ },
644
+ /**
645
+ * 外部调用方法
646
+ * 校验数据
647
+ * @param {any} value 需要校验的数据
648
+ * @param {boolean} 是否立即校验
649
+ * @return {Array|null} 校验内容
650
+ */
651
+ async onFieldChange(value, formtrigger = true) {
652
+ const { formData, localData, errShowType, validateCheck, validateTrigger, _isRequiredField, _realName } = this.form;
653
+ const name = _realName(this.name);
654
+ if (!value) {
655
+ value = this.form.formData[name];
656
+ }
657
+ // fixd by mehaotian 不在校验前清空信息,解决闪屏的问题
658
+ // this.errMsg = '';
659
+ // fix by mehaotian 解决没有检验规则的情况下,抛出错误的问题
660
+ const ruleLen = this.itemRules.rules && this.itemRules.rules.length;
661
+ if (!this.validator || !ruleLen || ruleLen === 0) return;
662
+ // 检验时机
663
+ // let trigger = this.isTrigger(this.itemRules.validateTrigger, this.validateTrigger, validateTrigger);
664
+ const isRequiredField = _isRequiredField(this.itemRules.rules || []);
665
+ let result = null;
666
+ // 只有等于 bind 时 ,才能开启时实校验
667
+ if (validateTrigger === 'bind' || formtrigger) {
668
+ // 校验当前表单项
669
+ result = await this.validator.validateUpdate(
670
+ {
671
+ [name]: value
672
+ },
673
+ formData
674
+ );
675
+ // 判断是否必填,非必填,不填不校验,填写才校验 ,暂时只处理 undefined 和空的情况
676
+ if (!isRequiredField && (value === undefined || value === '')) {
677
+ result = null;
678
+ }
679
+ // 判断错误信息显示类型
680
+ if (result && result.errorMessage) {
681
+ if (errShowType === 'undertext') {
682
+ // 获取错误信息
683
+ this.errMsg = !result ? '' : result.errorMessage;
684
+ }
685
+ if (errShowType === 'toast') {
686
+ uni.showToast({
687
+ title: result.errorMessage || '校验错误',
688
+ icon: 'none'
689
+ });
690
+ }
691
+ if (errShowType === 'modal') {
692
+ uni.showModal({
693
+ title: '提示',
694
+ content: result.errorMessage || '校验错误'
695
+ });
696
+ }
697
+ } else {
698
+ this.errMsg = '';
699
+ }
700
+ // 通知 form 组件更新事件
701
+ validateCheck(result ? result : null);
702
+ } else {
703
+ this.errMsg = '';
704
+ }
705
+ return result ? result : null;
706
+ },
707
+ /**
708
+ * 初始组件数据
709
+ */
710
+ init(type = false) {
711
+ const { validator, formRules, childrens, formData, localData, _realName, labelWidth, _getDataValue, _setDataValue } =
712
+ this.form || {};
713
+ // 对齐方式
714
+ this.localLabelAlign = this._justifyContent();
715
+ // 宽度
716
+ this.localLabelWidth = this._labelWidthUnit(labelWidth);
717
+ // 标签位置
718
+ this.localLabelPos = this._labelPosition();
719
+ // 将需要校验的子组件加入form 队列
720
+ this.form && type && childrens.push(this);
721
+ if (!validator || !formRules) return;
722
+ // 判断第一个 item
723
+ if (!this.form.isFirstBorder) {
724
+ this.form.isFirstBorder = true;
725
+ this.isFirstBorder = true;
726
+ }
727
+ // 判断 group 里的第一个 item
728
+ if (this.group) {
729
+ if (!this.group.isFirstBorder) {
730
+ this.group.isFirstBorder = true;
731
+ this.isFirstBorder = true;
732
+ }
733
+ }
734
+ this.border = this.form.border;
735
+ // 获取子域的真实名称
736
+ const name = _realName(this.name);
737
+ const itemRule = this.userRules || this.rules;
738
+ if (typeof formRules === 'object' && itemRule) {
739
+ // 子规则替换父规则
740
+ formRules[name] = {
741
+ rules: itemRule
742
+ };
743
+ validator.updateSchema(formRules);
744
+ }
745
+ // 注册校验规则
746
+ const itemRules = formRules[name] || {};
747
+ this.itemRules = itemRules;
748
+ // 注册校验函数
749
+ this.validator = validator;
750
+ // 默认值赋予
751
+ this.itemSetValue(_getDataValue(this.name, localData));
752
+ },
753
+ unInit() {
754
+ if (this.form) {
755
+ const { childrens, formData, _realName } = this.form;
756
+ childrens.forEach((item, index) => {
757
+ if (item === this) {
758
+ this.form.childrens.splice(index, 1);
759
+ delete formData[_realName(item.name)];
760
+ }
761
+ });
762
+ }
763
+ },
764
+ // 设置item 的值
765
+ itemSetValue(value) {
766
+ const name = this.form._realName(this.name);
767
+ const rules = this.itemRules.rules || [];
768
+ const val = this.form._getValue(name, value, rules);
769
+ this.form._setDataValue(name, this.form.formData, val);
770
+ return val;
771
+ },
772
+ /**
773
+ * 移除该表单项的校验结果
774
+ */
775
+ clearValidate() {
776
+ this.errMsg = '';
777
+ },
778
+ // 是否显示星号
779
+ _isRequired() {
780
+ // TODO 不根据规则显示 星号,考虑后续兼容
781
+ // if (this.form) {
782
+ // if (this.form._isRequiredField(this.itemRules.rules || []) && this.required) {
783
+ // return true
784
+ // }
785
+ // return false
786
+ // }
787
+ return this.required;
788
+ },
789
+ // 处理对齐方式
790
+ _justifyContent() {
791
+ if (this.form) {
792
+ const { labelAlign } = this.form;
793
+ let labelAli = this.labelAlign ? this.labelAlign : labelAlign;
794
+ if (labelAli === 'left') return 'flex-start';
795
+ if (labelAli === 'center') return 'center';
796
+ if (labelAli === 'right') return 'flex-end';
797
+ }
798
+ return 'flex-start';
799
+ },
800
+ // 处理 label宽度单位 ,继承父元素的值
801
+ _labelWidthUnit(labelWidth) {
802
+ // if (this.form) {
803
+ // const {
804
+ // labelWidth
805
+ // } = this.form
806
+ return this.num2px(this.labelWidth ? this.labelWidth : labelWidth || (this.label ? 65 : 'auto'));
807
+ // }
808
+ // return '65px'
809
+ },
810
+ // 处理 label 位置
811
+ _labelPosition() {
812
+ if (this.form) return this.form.labelPosition || 'left';
813
+ return 'left';
814
+ },
815
+ /**
816
+ * 触发时机
817
+ * @param {Object} rule 当前规则内时机
818
+ * @param {Object} itemRlue 当前组件时机
819
+ * @param {Object} parentRule 父组件时机
820
+ */
821
+ isTrigger(rule, itemRlue, parentRule) {
822
+ // bind submit
823
+ if (rule === 'submit' || !rule) {
824
+ if (rule === undefined) {
825
+ if (itemRlue !== 'bind') {
826
+ if (!itemRlue) {
827
+ return parentRule === '' ? 'bind' : 'submit';
828
+ }
829
+ return 'submit';
830
+ }
831
+ return 'bind';
832
+ }
833
+ return 'submit';
834
+ }
835
+ return 'bind';
836
+ },
837
+ num2px(num) {
838
+ if (typeof num === 'number') {
839
+ return `${num}px`;
840
+ }
841
+ return num;
842
+ }
843
+ }
844
+ };
845
+ </script>
846
+ <style>
847
+ @import 'style.css';
848
+ </style>