@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,515 @@
1
- <template>
2
1
  <view class="uni-easyinput" :class="{ 'uni-easyinput-error': msg }" :style="boxStyle">
3
2
  <view class="uni-easyinput__content" :class="inputContentClass" :style="inputContentStyle">
4
3
  <uni-icons
5
4
  v-if="prefixIcon"
6
5
  class="content-clear-icon"
7
6
  :type="prefixIcon"
8
7
  color="#c0c4cc"
9
8
  @click="onClickIcon('prefix')"
10
9
  size="22"
11
10
  ></uni-icons>
12
11
  <textarea
13
12
  v-if="type === 'textarea'"
14
13
  class="uni-easyinput__content-textarea"
15
14
  :class="{ 'input-padding': inputBorder }"
16
15
  :name="name"
17
16
  :value="val"
18
17
  :placeholder="placeholder"
19
18
  :placeholderStyle="placeholderStyle"
20
19
  :disabled="disabled"
21
20
  placeholder-class="uni-easyinput__placeholder-class"
22
21
  :maxlength="inputMaxlength"
23
22
  :focus="focused"
24
23
  :autoHeight="autoHeight"
25
24
  :cursor-spacing="cursorSpacing"
26
25
  @input="onInput"
27
26
  @blur="_Blur"
28
27
  @focus="_Focus"
29
28
  @confirm="onConfirm"
30
29
  @keyboardheightchange="onkeyboardheightchange"
31
30
  ></textarea>
32
31
  <input
33
32
  v-else
34
33
  :type="type === 'password' ? 'text' : type"
35
34
  class="uni-easyinput__content-input"
36
35
  :style="inputStyle"
37
36
  :name="name"
38
37
  :value="val"
39
38
  :password="!showPassword && type === 'password'"
40
39
  :placeholder="placeholder"
41
40
  :placeholderStyle="placeholderStyle"
42
41
  placeholder-class="uni-easyinput__placeholder-class"
43
42
  :disabled="disabled"
44
43
  :maxlength="inputMaxlength"
45
44
  :focus="focused"
46
45
  :confirmType="confirmType"
47
46
  :cursor-spacing="cursorSpacing"
48
47
  @focus="_Focus"
49
48
  @blur="_Blur"
50
49
  @input="onInput"
51
50
  @confirm="onConfirm"
52
51
  @keyboardheightchange="onkeyboardheightchange"
53
52
  />
54
53
  <template v-if="type === 'password' && passwordIcon">
55
54
  <!-- 开启密码时显示小眼睛 -->
56
55
  <uni-icons
57
56
  v-if="isVal"
58
57
  class="content-clear-icon"
59
58
  :class="{ 'is-textarea-icon': type === 'textarea' }"
60
59
  :type="showPassword ? 'eye-slash-filled' : 'eye-filled'"
61
60
  :size="22"
62
61
  :color="focusShow ? primaryColor : '#c0c4cc'"
63
62
  @click="onEyes"
64
63
  ></uni-icons>
65
64
  </template>
66
65
  <template v-else-if="suffixIcon">
67
66
  <uni-icons
68
67
  v-if="suffixIcon"
69
68
  class="content-clear-icon"
70
69
  :type="suffixIcon"
71
70
  color="#c0c4cc"
72
71
  @click="onClickIcon('suffix')"
73
72
  size="22"
74
73
  ></uni-icons>
75
74
  </template>
76
75
  <template v-else>
77
76
  <uni-icons
78
77
  v-if="clearable && isVal && !disabled && type !== 'textarea'"
79
78
  class="content-clear-icon"
80
79
  :class="{ 'is-textarea-icon': type === 'textarea' }"
81
80
  type="clear"
82
81
  :size="clearSize"
83
82
  :color="msg ? '#dd524d' : focusShow ? primaryColor : '#c0c4cc'"
84
83
  @click="onClear"
85
84
  ></uni-icons>
86
85
  </template>
87
86
  <slot name="right"></slot>
88
87
  </view>
89
88
  </view>
90
89
  * Easyinput 输入框
91
90
  * @description 此组件可以实现表单的输入与校验,包括 "text" 和 "textarea" 类型。
92
91
  * @tutorial https://ext.dcloud.net.cn/plugin?id=3455
93
92
  * @property {String} value 输入内容
94
93
  * @property {String } type 输入框的类型(默认text) password/text/textarea/..
95
94
  * @value text 文本输入键盘
96
95
  * @value textarea 多行文本输入键盘
97
96
  * @value password 密码输入键盘
98
97
  * @value number 数字输入键盘,注意iOS上app-vue弹出的数字键盘并非9宫格方式
99
98
  * @value idcard 身份证输入键盘,信、支付宝、百度、QQ小程序
100
99
  * @value digit 带小数点的数字键盘 ,App的nvue页面、微信、支付宝、百度、头条、QQ小程序支持
101
100
  * @property {Boolean} clearable 是否显示右侧清空内容的图标控件,点击可清空输入框内容(默认true)
102
101
  * @property {Boolean} autoHeight 是否自动增高输入区域,type为textarea时有效(默认true)
103
102
  * @property {String } placeholder 输入框的提示文字
104
103
  * @property {String } placeholderStyle placeholder的样式(内联样式,字符串),如"color: #ddd"
105
104
  * @property {Boolean} focus 是否自动获得焦点(默认false)
106
105
  * @property {Boolean} disabled 是否禁用(默认false)
107
106
  * @property {Number } maxlength 最大输入长度,设置为 -1 的时候不限制最大长度(默认140)
108
107
  * @property {String } confirmType 设置键盘右下角按钮的文字,仅在type="text"时生效(默认done)
109
108
  * @property {Number } clearSize 清除图标的大小,单位px(默认15)
110
109
  * @property {String} prefixIcon 输入框头部图标
111
110
  * @property {String} suffixIcon 输入框尾部图标
112
111
  * @property {String} primaryColor 设置主题色(默认#2979ff)
113
112
  * @property {Boolean} trim 是否自动去除两端的空格
114
113
  * @property {Boolean} cursorSpacing 指定光标与键盘的距离,单位 px
115
114
  * @value both 去除两端空格
116
115
  * @value left 去除左侧空格
117
116
  * @value right 去除右侧空格
118
117
  * @value start 去除左侧空格
119
118
  * @value end 去除右侧空格
120
119
  * @value all 去除全部空格
121
120
  * @value none 不去除空格
122
121
  * @property {Boolean} inputBorder 是否显示input输入框的边框(默认true)
123
122
  * @property {Boolean} passwordIcon type=password时是否显示小眼睛图标
124
123
  * @property {Object} styles 自定义颜色
125
124
  * @event {Function} input 输入框内容发生变化时触发
126
125
  * @event {Function} focus 输入框获得焦点时触发
127
126
  * @event {Function} blur 输入框失去焦点时触发
128
127
  * @event {Function} confirm 点击完成按钮时触发
129
128
  * @event {Function} iconClick 点击图标时触发
130
129
  * @example <uni-easyinput v-model="mobile"></uni-easyinput>
131
130
  */
132
131
  let classess = '';
133
132
  for (let key in obj) {
134
133
  const val = obj[key];
135
134
  if (val) {
136
135
  classess += `${key} `;
137
136
  }
138
137
  }
139
138
  return classess;
140
139
  let style = '';
141
140
  for (let key in obj) {
142
141
  const val = obj[key];
143
142
  style += `${key}:${val};`;
144
143
  }
145
144
  return style;
146
145
  name: 'uni-easyinput',
147
146
  emits: [
148
147
  'click',
149
148
  'iconClick',
150
149
  'update:modelValue',
151
150
  'input',
152
151
  'focus',
153
152
  'blur',
154
153
  'confirm',
155
154
  'clear',
156
155
  'eyes',
157
156
  'change',
158
157
  'keyboardheightchange'
159
158
  ],
160
159
  model: {
161
160
  prop: 'modelValue',
162
161
  event: 'update:modelValue'
163
162
  },
164
163
  options: {
165
164
  virtualHost: true
166
165
  },
167
166
  inject: {
168
167
  form: {
169
168
  from: 'uniForm',
170
169
  default: null
171
170
  },
172
171
  formItem: {
173
172
  from: 'uniFormItem',
174
173
  default: null
175
174
  }
176
175
  },
177
176
  props: {
178
177
  name: String,
179
178
  value: [Number, String],
180
179
  modelValue: [Number, String],
181
180
  type: {
182
181
  type: String,
183
182
  default: 'text'
184
183
  },
185
184
  clearable: {
186
185
  type: Boolean,
187
186
  default: true
188
187
  },
189
188
  autoHeight: {
190
189
  type: Boolean,
191
190
  default: false
192
191
  },
193
192
  placeholder: {
194
193
  type: String,
195
194
  default: ' '
196
195
  },
197
196
  placeholderStyle: String,
198
197
  focus: {
199
198
  type: Boolean,
200
199
  default: false
201
200
  },
202
201
  disabled: {
203
202
  type: Boolean,
204
203
  default: false
205
204
  },
206
205
  maxlength: {
207
206
  type: [Number, String],
208
207
  default: 140
209
208
  },
210
209
  confirmType: {
211
210
  type: String,
212
211
  default: 'done'
213
212
  },
214
213
  clearSize: {
215
214
  type: [Number, String],
216
215
  default: 24
217
216
  },
218
217
  inputBorder: {
219
218
  type: Boolean,
220
219
  default: true
221
220
  },
222
221
  prefixIcon: {
223
222
  type: String,
224
223
  default: ''
225
224
  },
226
225
  suffixIcon: {
227
226
  type: String,
228
227
  default: ''
229
228
  },
230
229
  trim: {
231
230
  type: [Boolean, String],
232
231
  default: false
233
232
  },
234
233
  cursorSpacing: {
235
234
  type: Number,
236
235
  default: 0
237
236
  },
238
237
  passwordIcon: {
239
238
  type: Boolean,
240
239
  default: true
241
240
  },
242
241
  primaryColor: {
243
242
  type: String,
244
243
  default: '#2979ff'
245
244
  },
246
245
  styles: {
247
246
  type: Object,
248
247
  default() {
249
248
  return {
250
249
  color: '#333',
251
250
  backgroundColor: '#fff',
252
251
  disableColor: '#F7F6F6',
253
252
  borderColor: '#e5e5e5'
254
253
  };
255
254
  }
256
255
  },
257
256
  errorMessage: {
258
257
  type: [String, Boolean],
259
258
  default: ''
260
259
  }
261
260
  },
262
261
  data() {
263
262
  return {
264
263
  focused: false,
265
264
  val: '',
266
265
  showMsg: '',
267
266
  border: false,
268
267
  isFirstBorder: false,
269
268
  showClearIcon: false,
270
269
  showPassword: false,
271
270
  focusShow: false,
272
271
  localMsg: '',
273
272
  isEnter: false // 用于判断当前是否是使用回车操作
274
273
  };
275
274
  },
276
275
  computed: {
277
276
  // 输入框内是否有值
278
277
  isVal() {
279
278
  const val = this.val;
280
279
  // fixed by mehaotian 处理值为0的情况,字符串0不在处理范围
281
280
  if (val || val === 0) {
282
281
  return true;
283
282
  }
284
283
  return false;
285
284
  },
286
285
  msg() {
287
286
  // console.log('computed', this.form, this.formItem);
288
287
  // if (this.form) {
289
288
  // return this.errorMessage || this.formItem.errMsg;
290
289
  // }
291
290
  // TODO 处理头条 formItem 中 errMsg 不更新的问题
292
291
  return this.localMsg || this.errorMessage;
293
292
  },
294
293
  // 因为uniapp的input组件的maxlength组件必须要数值,这里转为数值,用户可以传入字符串数值
295
294
  inputMaxlength() {
296
295
  return Number(this.maxlength);
297
296
  },
298
297
  // 处理外层样式的style
299
298
  boxStyle() {
300
299
  return `color:${this.inputBorder && this.msg ? '#e43d33' : this.styles.color};`;
301
300
  },
302
301
  // input 内容的类和样式处理
303
302
  inputContentClass() {
304
303
  return obj2strClass({
305
304
  'is-input-border': this.inputBorder,
306
305
  'is-input-error-border': this.inputBorder && this.msg,
307
306
  'is-textarea': this.type === 'textarea',
308
307
  'is-disabled': this.disabled,
309
308
  'is-focused': this.focusShow
310
309
  });
311
310
  },
312
311
  inputContentStyle() {
313
312
  const focusColor = this.focusShow ? this.primaryColor : this.styles.borderColor;
314
313
  const borderColor = this.inputBorder && this.msg ? '#dd524d' : focusColor;
315
314
  return obj2strStyle({
316
315
  'border-color': borderColor || '#e5e5e5',
317
316
  'background-color': this.disabled ? this.styles.disableColor : this.styles.backgroundColor
318
317
  });
319
318
  },
320
319
  // input右侧样式
321
320
  inputStyle() {
322
321
  const paddingRight = this.type === 'password' || this.clearable || this.prefixIcon ? '' : '10px';
323
322
  return obj2strStyle({
324
323
  'padding-right': paddingRight,
325
324
  'padding-left': this.prefixIcon ? '' : '10px'
326
325
  });
327
326
  }
328
327
  },
329
328
  watch: {
330
329
  value(newVal) {
331
330
  this.val = newVal;
332
331
  },
333
332
  modelValue(newVal) {
334
333
  this.val = newVal;
335
334
  },
336
335
  focus(newVal) {
337
336
  this.$nextTick(() => {
338
337
  this.focused = this.focus;
339
338
  this.focusShow = this.focus;
340
339
  });
341
340
  }
342
341
  },
343
342
  created() {
344
343
  this.init();
345
344
  // TODO 处理头条vue3 computed 不监听 inject 更改的问题(formItem.errMsg)
346
345
  if (this.form && this.formItem) {
347
346
  this.$watch('formItem.errMsg', (newVal) => {
348
347
  this.localMsg = newVal;
349
348
  });
350
349
  }
351
350
  },
352
351
  mounted() {
353
352
  this.$nextTick(() => {
354
353
  this.focused = this.focus;
355
354
  this.focusShow = this.focus;
356
355
  });
357
356
  },
358
357
  methods: {
359
358
  /**
360
359
  * 初始化变量值
361
360
  */
362
361
  init() {
363
362
  if (this.value || this.value === 0) {
364
363
  this.val = this.value;
365
364
  } else if (this.modelValue || this.modelValue === 0 || this.modelValue === '') {
366
365
  this.val = this.modelValue;
367
366
  } else {
368
367
  this.val = null;
369
368
  }
370
369
  },
371
370
  /**
372
371
  * 点击图标时触发
373
372
  * @param {Object} type
374
373
  */
375
374
  onClickIcon(type) {
376
375
  this.$emit('iconClick', type);
377
376
  },
378
377
  /**
379
378
  * 显示隐藏内容,密码框时生效
380
379
  */
381
380
  onEyes() {
382
381
  this.showPassword = !this.showPassword;
383
382
  this.$emit('eyes', this.showPassword);
384
383
  },
385
384
  /**
386
385
  * 输入时触发
387
386
  * @param {Object} event
388
387
  */
389
388
  onInput(event) {
390
389
  let value = event.detail.value;
391
390
  // 判断是否去除空格
392
391
  if (this.trim) {
393
392
  if (typeof this.trim === 'boolean' && this.trim) {
394
393
  value = this.trimStr(value);
395
394
  }
396
395
  if (typeof this.trim === 'string') {
397
396
  value = this.trimStr(value, this.trim);
398
397
  }
399
398
  }
400
399
  if (this.errMsg) this.errMsg = '';
401
400
  this.val = value;
402
401
  // TODO 兼容 vue2
403
402
  this.$emit('input', value);
404
403
  // TODO 兼容 vue3
405
404
  this.$emit('update:modelValue', value);
406
405
  },
407
406
  /**
408
407
  * 外部调用方法
409
408
  * 获取焦点时触发
410
409
  * @param {Object} event
411
410
  */
412
411
  onFocus() {
413
412
  this.$nextTick(() => {
414
413
  this.focused = true;
415
414
  });
416
415
  this.$emit('focus', null);
417
416
  },
418
417
  _Focus(event) {
419
418
  this.focusShow = true;
420
419
  this.$emit('focus', event);
421
420
  },
422
421
  /**
423
422
  * 外部调用方法
424
423
  * 失去焦点时触发
425
424
  * @param {Object} event
426
425
  */
427
426
  onBlur() {
428
427
  this.focused = false;
429
428
  this.$emit('focus', null);
430
429
  },
431
430
  _Blur(event) {
432
431
  let value = event.detail.value;
433
432
  this.focusShow = false;
434
433
  this.$emit('blur', event);
435
434
  // 根据类型返回值,在event中获取的值理论上讲都是string
436
435
  if (this.isEnter === false) {
437
436
  this.$emit('change', this.val);
438
437
  }
439
438
  // 失去焦点时参与表单校验
440
439
  if (this.form && this.formItem) {
441
440
  const { validateTrigger } = this.form;
442
441
  if (validateTrigger === 'blur') {
443
442
  this.formItem.onFieldChange();
444
443
  }
445
444
  }
446
445
  },
447
446
  /**
448
447
  * 按下键盘的发送键
449
448
  * @param {Object} e
450
449
  */
451
450
  onConfirm(e) {
452
451
  this.$emit('confirm', this.val);
453
452
  this.isEnter = true;
454
453
  this.$emit('change', this.val);
455
454
  this.$nextTick(() => {
456
455
  this.isEnter = false;
457
456
  });
458
457
  },
459
458
  /**
460
459
  * 清理内容
461
460
  * @param {Object} event
462
461
  */
463
462
  onClear(event) {
464
463
  this.val = '';
465
464
  // TODO 兼容 vue2
466
465
  this.$emit('input', '');
467
466
  // TODO 兼容 vue2
468
467
  // TODO 兼容 vue3
469
468
  this.$emit('update:modelValue', '');
470
469
  // 点击叉号触发
471
470
  this.$emit('clear');
472
471
  },
473
472
  /**
474
473
  * 键盘高度发生变化的时候触发此事件
475
474
  * 兼容性:微信小程序2.7.0+、App 3.1.0+
476
475
  * @param {Object} event
477
476
  */
478
477
  onkeyboardheightchange(event) {
479
478
  this.$emit('keyboardheightchange', event);
480
479
  },
481
480
  /**
482
481
  * 去除空格
483
482
  */
484
483
  trimStr(str, pos = 'both') {
485
484
  if (pos === 'both') {
486
485
  return str.trim();
487
486
  } else if (pos === 'left') {
488
487
  return str.trimLeft();
489
488
  } else if (pos === 'right') {
490
489
  return str.trimRight();
491
490
  } else if (pos === 'start') {
492
491
  return str.trimStart();
493
492
  } else if (pos === 'end') {
494
493
  return str.trimEnd();
495
494
  } else if (pos === 'all') {
496
495
  return str.replace(/\s+/g, '');
497
496
  } else if (pos === 'none') {
498
497
  return str;
499
498
  }
500
499
  return str;
501
500
  }
502
501
  }
502
+ <template>
503
+ <view class="uni-easyinput" :class="{ 'uni-easyinput-error': msg }" :style="boxStyle">
504
+ <view class="uni-easyinput__content" :class="inputContentClass" :style="inputContentStyle">
505
+ <uni-icons
506
+ v-if="prefixIcon"
507
+ class="content-clear-icon"
508
+ :type="prefixIcon"
509
+ color="#c0c4cc"
510
+ @click="onClickIcon('prefix')"
511
+ size="22"
512
+ ></uni-icons>
513
+ <textarea
514
+ v-if="type === 'textarea'"
515
+ class="uni-easyinput__content-textarea"
516
+ :class="{ 'input-padding': inputBorder }"
517
+ :name="name"
518
+ :value="val"
519
+ :placeholder="placeholder"
520
+ :placeholderStyle="placeholderStyle"
521
+ :disabled="disabled"
522
+ placeholder-class="uni-easyinput__placeholder-class"
523
+ :maxlength="inputMaxlength"
524
+ :focus="focused"
525
+ :autoHeight="autoHeight"
526
+ :cursor-spacing="cursorSpacing"
527
+ @input="onInput"
528
+ @blur="_Blur"
529
+ @focus="_Focus"
530
+ @confirm="onConfirm"
531
+ @keyboardheightchange="onkeyboardheightchange"
532
+ ></textarea>
533
+ <input
534
+ v-else
535
+ :type="type === 'password' ? 'text' : type"
536
+ class="uni-easyinput__content-input"
537
+ :style="inputStyle"
538
+ :name="name"
539
+ :value="val"
540
+ :password="!showPassword && type === 'password'"
541
+ :placeholder="placeholder"
542
+ :placeholderStyle="placeholderStyle"
543
+ placeholder-class="uni-easyinput__placeholder-class"
544
+ :disabled="disabled"
545
+ :maxlength="inputMaxlength"
546
+ :focus="focused"
547
+ :confirmType="confirmType"
548
+ :cursor-spacing="cursorSpacing"
549
+ @focus="_Focus"
550
+ @blur="_Blur"
551
+ @input="onInput"
552
+ @confirm="onConfirm"
553
+ @keyboardheightchange="onkeyboardheightchange"
554
+ />
555
+ <template v-if="type === 'password' && passwordIcon">
556
+ <!-- 开启密码时显示小眼睛 -->
557
+ <uni-icons
558
+ v-if="isVal"
559
+ class="content-clear-icon"
560
+ :class="{ 'is-textarea-icon': type === 'textarea' }"
561
+ :type="showPassword ? 'eye-slash-filled' : 'eye-filled'"
562
+ :size="22"
563
+ :color="focusShow ? primaryColor : '#c0c4cc'"
564
+ @click="onEyes"
565
+ ></uni-icons>
566
+ </template>
567
+ <template v-else-if="suffixIcon">
568
+ <uni-icons
569
+ v-if="suffixIcon"
570
+ class="content-clear-icon"
571
+ :type="suffixIcon"
572
+ color="#c0c4cc"
573
+ @click="onClickIcon('suffix')"
574
+ size="22"
575
+ ></uni-icons>
576
+ </template>
577
+ <template v-else>
578
+ <uni-icons
579
+ v-if="clearable && isVal && !disabled && type !== 'textarea'"
580
+ class="content-clear-icon"
581
+ :class="{ 'is-textarea-icon': type === 'textarea' }"
582
+ type="clear"
583
+ :size="clearSize"
584
+ :color="msg ? '#dd524d' : focusShow ? primaryColor : '#c0c4cc'"
585
+ @click="onClear"
586
+ ></uni-icons>
587
+ </template>
588
+ <slot name="right"></slot>
589
+ </view>
590
+ </view>
591
+ </template>
592
+ <script>
593
+ /**
594
+ * Easyinput 输入框
595
+ * @description 此组件可以实现表单的输入与校验,包括 "text" 和 "textarea" 类型。
596
+ * @tutorial https://ext.dcloud.net.cn/plugin?id=3455
597
+ * @property {String} value 输入内容
598
+ * @property {String } type 输入框的类型(默认text) password/text/textarea/..
599
+ * @value text 文本输入键盘
600
+ * @value textarea 多行文本输入键盘
601
+ * @value password 密码输入键盘
602
+ * @value number 数字输入键盘,注意iOS上app-vue弹出的数字键盘并非9宫格方式
603
+ * @value idcard 身份证输入键盘,信、支付宝、百度、QQ小程序
604
+ * @value digit 带小数点的数字键盘 ,App的nvue页面、微信、支付宝、百度、头条、QQ小程序支持
605
+ * @property {Boolean} clearable 是否显示右侧清空内容的图标控件,点击可清空输入框内容(默认true)
606
+ * @property {Boolean} autoHeight 是否自动增高输入区域,type为textarea时有效(默认true)
607
+ * @property {String } placeholder 输入框的提示文字
608
+ * @property {String } placeholderStyle placeholder的样式(内联样式,字符串),如"color: #ddd"
609
+ * @property {Boolean} focus 是否自动获得焦点(默认false)
610
+ * @property {Boolean} disabled 是否禁用(默认false)
611
+ * @property {Number } maxlength 最大输入长度,设置为 -1 的时候不限制最大长度(默认140)
612
+ * @property {String } confirmType 设置键盘右下角按钮的文字,仅在type="text"时生效(默认done)
613
+ * @property {Number } clearSize 清除图标的大小,单位px(默认15)
614
+ * @property {String} prefixIcon 输入框头部图标
615
+ * @property {String} suffixIcon 输入框尾部图标
616
+ * @property {String} primaryColor 设置主题色(默认#2979ff)
617
+ * @property {Boolean} trim 是否自动去除两端的空格
618
+ * @property {Boolean} cursorSpacing 指定光标与键盘的距离,单位 px
619
+ * @value both 去除两端空格
620
+ * @value left 去除左侧空格
621
+ * @value right 去除右侧空格
622
+ * @value start 去除左侧空格
623
+ * @value end 去除右侧空格
624
+ * @value all 去除全部空格
625
+ * @value none 不去除空格
626
+ * @property {Boolean} inputBorder 是否显示input输入框的边框(默认true)
627
+ * @property {Boolean} passwordIcon type=password时是否显示小眼睛图标
628
+ * @property {Object} styles 自定义颜色
629
+ * @event {Function} input 输入框内容发生变化时触发
630
+ * @event {Function} focus 输入框获得焦点时触发
631
+ * @event {Function} blur 输入框失去焦点时触发
632
+ * @event {Function} confirm 点击完成按钮时触发
633
+ * @event {Function} iconClick 点击图标时触发
634
+ * @example <uni-easyinput v-model="mobile"></uni-easyinput>
635
+ */
636
+ function obj2strClass(obj) {
637
+ let classess = '';
638
+ for (let key in obj) {
639
+ const val = obj[key];
640
+ if (val) {
641
+ classess += `${key} `;
642
+ }
643
+ }
644
+ return classess;
645
+ }
646
+ function obj2strStyle(obj) {
647
+ let style = '';
648
+ for (let key in obj) {
649
+ const val = obj[key];
650
+ style += `${key}:${val};`;
651
+ }
652
+ return style;
653
+ }
654
+ export default {
655
+ name: 'uni-easyinput',
656
+ emits: [
657
+ 'click',
658
+ 'iconClick',
659
+ 'update:modelValue',
660
+ 'input',
661
+ 'focus',
662
+ 'blur',
663
+ 'confirm',
664
+ 'clear',
665
+ 'eyes',
666
+ 'change',
667
+ 'keyboardheightchange'
668
+ ],
669
+ model: {
670
+ prop: 'modelValue',
671
+ event: 'update:modelValue'
672
+ },
673
+ options: {
674
+ virtualHost: true
675
+ },
676
+ inject: {
677
+ form: {
678
+ from: 'uniForm',
679
+ default: null
680
+ },
681
+ formItem: {
682
+ from: 'uniFormItem',
683
+ default: null
684
+ }
685
+ },
686
+ props: {
687
+ name: String,
688
+ value: [Number, String],
689
+ modelValue: [Number, String],
690
+ type: {
691
+ type: String,
692
+ default: 'text'
693
+ },
694
+ clearable: {
695
+ type: Boolean,
696
+ default: true
697
+ },
698
+ autoHeight: {
699
+ type: Boolean,
700
+ default: false
701
+ },
702
+ placeholder: {
703
+ type: String,
704
+ default: ' '
705
+ },
706
+ placeholderStyle: String,
707
+ focus: {
708
+ type: Boolean,
709
+ default: false
710
+ },
711
+ disabled: {
712
+ type: Boolean,
713
+ default: false
714
+ },
715
+ maxlength: {
716
+ type: [Number, String],
717
+ default: 140
718
+ },
719
+ confirmType: {
720
+ type: String,
721
+ default: 'done'
722
+ },
723
+ clearSize: {
724
+ type: [Number, String],
725
+ default: 24
726
+ },
727
+ inputBorder: {
728
+ type: Boolean,
729
+ default: true
730
+ },
731
+ prefixIcon: {
732
+ type: String,
733
+ default: ''
734
+ },
735
+ suffixIcon: {
736
+ type: String,
737
+ default: ''
738
+ },
739
+ trim: {
740
+ type: [Boolean, String],
741
+ default: false
742
+ },
743
+ cursorSpacing: {
744
+ type: Number,
745
+ default: 0
746
+ },
747
+ passwordIcon: {
748
+ type: Boolean,
749
+ default: true
750
+ },
751
+ primaryColor: {
752
+ type: String,
753
+ default: '#2979ff'
754
+ },
755
+ styles: {
756
+ type: Object,
757
+ default() {
758
+ return {
759
+ color: '#333',
760
+ backgroundColor: '#fff',
761
+ disableColor: '#F7F6F6',
762
+ borderColor: '#e5e5e5'
763
+ };
764
+ }
765
+ },
766
+ errorMessage: {
767
+ type: [String, Boolean],
768
+ default: ''
769
+ }
770
+ },
771
+ data() {
772
+ return {
773
+ focused: false,
774
+ val: '',
775
+ showMsg: '',
776
+ border: false,
777
+ isFirstBorder: false,
778
+ showClearIcon: false,
779
+ showPassword: false,
780
+ focusShow: false,
781
+ localMsg: '',
782
+ isEnter: false // 用于判断当前是否是使用回车操作
783
+ };
784
+ },
785
+ computed: {
786
+ // 输入框内是否有值
787
+ isVal() {
788
+ const val = this.val;
789
+ // fixed by mehaotian 处理值为0的情况,字符串0不在处理范围
790
+ if (val || val === 0) {
791
+ return true;
792
+ }
793
+ return false;
794
+ },
795
+ msg() {
796
+ // console.log('computed', this.form, this.formItem);
797
+ // if (this.form) {
798
+ // return this.errorMessage || this.formItem.errMsg;
799
+ // }
800
+ // TODO 处理头条 formItem 中 errMsg 不更新的问题
801
+ return this.localMsg || this.errorMessage;
802
+ },
803
+ // 因为uniapp的input组件的maxlength组件必须要数值,这里转为数值,用户可以传入字符串数值
804
+ inputMaxlength() {
805
+ return Number(this.maxlength);
806
+ },
807
+ // 处理外层样式的style
808
+ boxStyle() {
809
+ return `color:${this.inputBorder && this.msg ? '#e43d33' : this.styles.color};`;
810
+ },
811
+ // input 内容的类和样式处理
812
+ inputContentClass() {
813
+ return obj2strClass({
814
+ 'is-input-border': this.inputBorder,
815
+ 'is-input-error-border': this.inputBorder && this.msg,
816
+ 'is-textarea': this.type === 'textarea',
817
+ 'is-disabled': this.disabled,
818
+ 'is-focused': this.focusShow
819
+ });
820
+ },
821
+ inputContentStyle() {
822
+ const focusColor = this.focusShow ? this.primaryColor : this.styles.borderColor;
823
+ const borderColor = this.inputBorder && this.msg ? '#dd524d' : focusColor;
824
+ return obj2strStyle({
825
+ 'border-color': borderColor || '#e5e5e5',
826
+ 'background-color': this.disabled ? this.styles.disableColor : this.styles.backgroundColor
827
+ });
828
+ },
829
+ // input右侧样式
830
+ inputStyle() {
831
+ const paddingRight = this.type === 'password' || this.clearable || this.prefixIcon ? '' : '10px';
832
+ return obj2strStyle({
833
+ 'padding-right': paddingRight,
834
+ 'padding-left': this.prefixIcon ? '' : '10px'
835
+ });
836
+ }
837
+ },
838
+ watch: {
839
+ value(newVal) {
840
+ this.val = newVal;
841
+ },
842
+ modelValue(newVal) {
843
+ this.val = newVal;
844
+ },
845
+ focus(newVal) {
846
+ this.$nextTick(() => {
847
+ this.focused = this.focus;
848
+ this.focusShow = this.focus;
849
+ });
850
+ }
851
+ },
852
+ created() {
853
+ this.init();
854
+ // TODO 处理头条vue3 computed 不监听 inject 更改的问题(formItem.errMsg)
855
+ if (this.form && this.formItem) {
856
+ this.$watch('formItem.errMsg', (newVal) => {
857
+ this.localMsg = newVal;
858
+ });
859
+ }
860
+ },
861
+ mounted() {
862
+ this.$nextTick(() => {
863
+ this.focused = this.focus;
864
+ this.focusShow = this.focus;
865
+ });
866
+ },
867
+ methods: {
868
+ /**
869
+ * 初始化变量值
870
+ */
871
+ init() {
872
+ if (this.value || this.value === 0) {
873
+ this.val = this.value;
874
+ } else if (this.modelValue || this.modelValue === 0 || this.modelValue === '') {
875
+ this.val = this.modelValue;
876
+ } else {
877
+ this.val = null;
878
+ }
879
+ },
880
+ /**
881
+ * 点击图标时触发
882
+ * @param {Object} type
883
+ */
884
+ onClickIcon(type) {
885
+ this.$emit('iconClick', type);
886
+ },
887
+ /**
888
+ * 显示隐藏内容,密码框时生效
889
+ */
890
+ onEyes() {
891
+ this.showPassword = !this.showPassword;
892
+ this.$emit('eyes', this.showPassword);
893
+ },
894
+ /**
895
+ * 输入时触发
896
+ * @param {Object} event
897
+ */
898
+ onInput(event) {
899
+ let value = event.detail.value;
900
+ // 判断是否去除空格
901
+ if (this.trim) {
902
+ if (typeof this.trim === 'boolean' && this.trim) {
903
+ value = this.trimStr(value);
904
+ }
905
+ if (typeof this.trim === 'string') {
906
+ value = this.trimStr(value, this.trim);
907
+ }
908
+ }
909
+ if (this.errMsg) this.errMsg = '';
910
+ this.val = value;
911
+ // TODO 兼容 vue2
912
+ this.$emit('input', value);
913
+ // TODO 兼容 vue3
914
+ this.$emit('update:modelValue', value);
915
+ },
916
+ /**
917
+ * 外部调用方法
918
+ * 获取焦点时触发
919
+ * @param {Object} event
920
+ */
921
+ onFocus() {
922
+ this.$nextTick(() => {
923
+ this.focused = true;
924
+ });
925
+ this.$emit('focus', null);
926
+ },
927
+ _Focus(event) {
928
+ this.focusShow = true;
929
+ this.$emit('focus', event);
930
+ },
931
+ /**
932
+ * 外部调用方法
933
+ * 失去焦点时触发
934
+ * @param {Object} event
935
+ */
936
+ onBlur() {
937
+ this.focused = false;
938
+ this.$emit('focus', null);
939
+ },
940
+ _Blur(event) {
941
+ let value = event.detail.value;
942
+ this.focusShow = false;
943
+ this.$emit('blur', event);
944
+ // 根据类型返回值,在event中获取的值理论上讲都是string
945
+ if (this.isEnter === false) {
946
+ this.$emit('change', this.val);
947
+ }
948
+ // 失去焦点时参与表单校验
949
+ if (this.form && this.formItem) {
950
+ const { validateTrigger } = this.form;
951
+ if (validateTrigger === 'blur') {
952
+ this.formItem.onFieldChange();
953
+ }
954
+ }
955
+ },
956
+ /**
957
+ * 按下键盘的发送键
958
+ * @param {Object} e
959
+ */
960
+ onConfirm(e) {
961
+ this.$emit('confirm', this.val);
962
+ this.isEnter = true;
963
+ this.$emit('change', this.val);
964
+ this.$nextTick(() => {
965
+ this.isEnter = false;
966
+ });
967
+ },
968
+ /**
969
+ * 清理内容
970
+ * @param {Object} event
971
+ */
972
+ onClear(event) {
973
+ this.val = '';
974
+ // TODO 兼容 vue2
975
+ this.$emit('input', '');
976
+ // TODO 兼容 vue2
977
+ // TODO 兼容 vue3
978
+ this.$emit('update:modelValue', '');
979
+ // 点击叉号触发
980
+ this.$emit('clear');
981
+ },
982
+ /**
983
+ * 键盘高度发生变化的时候触发此事件
984
+ * 兼容性:微信小程序2.7.0+、App 3.1.0+
985
+ * @param {Object} event
986
+ */
987
+ onkeyboardheightchange(event) {
988
+ this.$emit('keyboardheightchange', event);
989
+ },
990
+ /**
991
+ * 去除空格
992
+ */
993
+ trimStr(str, pos = 'both') {
994
+ if (pos === 'both') {
995
+ return str.trim();
996
+ } else if (pos === 'left') {
997
+ return str.trimLeft();
998
+ } else if (pos === 'right') {
999
+ return str.trimRight();
1000
+ } else if (pos === 'start') {
1001
+ return str.trimStart();
1002
+ } else if (pos === 'end') {
1003
+ return str.trimEnd();
1004
+ } else if (pos === 'all') {
1005
+ return str.replace(/\s+/g, '');
1006
+ } else if (pos === 'none') {
1007
+ return str;
1008
+ }
1009
+ return str;
1010
+ }
1011
+ }
1012
+ };
1013
+ </script>
1014
+ <style>
1015
+ @import 'style.css';
1016
+ </style>