@tdesign/uniapp 0.7.3 → 0.8.0

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 (197) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +1 -1
  3. package/dist/action-sheet/README.md +1 -1
  4. package/dist/action-sheet/action-sheet.vue +158 -150
  5. package/dist/action-sheet/props.ts +2 -2
  6. package/dist/action-sheet/type.ts +1 -1
  7. package/dist/avatar/avatar.vue +89 -87
  8. package/dist/avatar-group/avatar-group.vue +69 -67
  9. package/dist/back-top/back-top.vue +60 -58
  10. package/dist/badge/badge.vue +69 -59
  11. package/dist/button/button.vue +121 -116
  12. package/dist/button/props.ts +2 -2
  13. package/dist/button/type.ts +1 -1
  14. package/dist/calendar/calendar-header.vue +4 -4
  15. package/dist/calendar/calendar.vue +308 -297
  16. package/dist/calendar/template.vue +1 -1
  17. package/dist/cascader/README.en-US.md +2 -1
  18. package/dist/cascader/README.md +2 -1
  19. package/dist/cascader/cascader.vue +340 -328
  20. package/dist/cascader/props.ts +6 -1
  21. package/dist/cascader/type.ts +6 -0
  22. package/dist/cell/cell.vue +127 -121
  23. package/dist/cell-group/cell-group.vue +32 -30
  24. package/dist/check-tag/check-tag.vue +73 -71
  25. package/dist/checkbox/checkbox.vue +127 -127
  26. package/dist/checkbox/props.ts +6 -6
  27. package/dist/checkbox/type.ts +3 -3
  28. package/dist/checkbox-group/checkbox-group.vue +175 -173
  29. package/dist/checkbox-group/props.ts +6 -6
  30. package/dist/checkbox-group/type.ts +4 -4
  31. package/dist/col/col.vue +26 -24
  32. package/dist/collapse/collapse.vue +83 -81
  33. package/dist/collapse-panel/collapse-panel.vue +121 -119
  34. package/dist/collapse-panel/props.ts +4 -4
  35. package/dist/collapse-panel/type.ts +2 -2
  36. package/dist/color-picker/README.md +1 -1
  37. package/dist/color-picker/color-picker.vue +324 -322
  38. package/dist/color-picker/props.ts +2 -2
  39. package/dist/color-picker/template.vue +14 -10
  40. package/dist/common/common.ts +1 -0
  41. package/dist/common/style/theme/index.css +5 -5
  42. package/dist/common/utils.js +7 -2
  43. package/dist/common/validator.js +172 -0
  44. package/dist/config-provider/README.en-US.md +184 -0
  45. package/dist/config-provider/README.md +234 -0
  46. package/dist/config-provider/config-provider.vue +105 -0
  47. package/dist/config-provider/config-store.js +70 -0
  48. package/dist/config-provider/props.ts +16 -0
  49. package/dist/config-provider/reactive-state.js +39 -0
  50. package/dist/config-provider/type.ts +401 -0
  51. package/dist/config-provider/use-config.js +29 -0
  52. package/dist/config-provider/utils.js +29 -0
  53. package/dist/count-down/count-down.vue +98 -97
  54. package/dist/date-time-picker/date-time-picker.vue +410 -395
  55. package/dist/demo/demo.vue +1 -0
  56. package/dist/dialog/dialog.vue +175 -173
  57. package/dist/divider/divider.vue +38 -36
  58. package/dist/draggable/draggable.vue +60 -58
  59. package/dist/drawer/README.md +1 -1
  60. package/dist/drawer/drawer.vue +48 -46
  61. package/dist/dropdown-item/dropdown-item.vue +209 -207
  62. package/dist/dropdown-item/props.ts +4 -4
  63. package/dist/dropdown-item/type.ts +3 -3
  64. package/dist/dropdown-menu/dropdown-menu.vue +93 -99
  65. package/dist/empty/empty.vue +43 -42
  66. package/dist/fab/fab.vue +88 -86
  67. package/dist/footer/footer.vue +36 -34
  68. package/dist/form/README.en-US.md +17 -24
  69. package/dist/form/README.md +18 -25
  70. package/dist/form/form.css +1 -166
  71. package/dist/form/form.vue +251 -236
  72. package/dist/form/props.ts +2 -21
  73. package/dist/form/type.ts +7 -70
  74. package/dist/form-item/README.en-US.md +4 -5
  75. package/dist/form-item/README.md +4 -5
  76. package/dist/form-item/form-item.css +69 -96
  77. package/dist/form-item/form-item.vue +315 -336
  78. package/dist/form-item/form-model.ts +125 -173
  79. package/dist/form-item/props.ts +4 -17
  80. package/dist/form-item/type.ts +43 -1
  81. package/dist/grid/grid.vue +53 -51
  82. package/dist/grid-item/grid-item.vue +121 -119
  83. package/dist/guide/README.md +1 -1
  84. package/dist/guide/guide.vue +281 -277
  85. package/dist/icon/README.md +2 -4
  86. package/dist/icon/icon.vue +78 -76
  87. package/dist/image/README.md +1 -1
  88. package/dist/image/image.vue +103 -101
  89. package/dist/image-viewer/image-viewer.vue +160 -158
  90. package/dist/image-viewer/props.ts +2 -2
  91. package/dist/image-viewer/type.ts +1 -1
  92. package/dist/index.js +3 -0
  93. package/dist/indexes/indexes.vue +264 -267
  94. package/dist/indexes-anchor/indexes-anchor.vue +41 -41
  95. package/dist/input/input.vue +192 -192
  96. package/dist/input/props.ts +6 -6
  97. package/dist/input/type.ts +3 -3
  98. package/dist/link/link.vue +73 -71
  99. package/dist/loading/loading.vue +59 -59
  100. package/dist/locale/ar_KW.ts +157 -0
  101. package/dist/locale/en_US.ts +146 -0
  102. package/dist/locale/it_IT.ts +145 -0
  103. package/dist/locale/ja_JP.ts +132 -0
  104. package/dist/locale/ko_KR.ts +132 -0
  105. package/dist/locale/ru_RU.ts +157 -0
  106. package/dist/locale/zh_CN.ts +133 -0
  107. package/dist/locale/zh_TW.ts +132 -0
  108. package/dist/message/message.vue +181 -173
  109. package/dist/message/props.ts +2 -2
  110. package/dist/message/type.ts +1 -1
  111. package/dist/message-item/message-item.vue +192 -184
  112. package/dist/mixins/using-config.js +39 -0
  113. package/dist/navbar/navbar.vue +201 -199
  114. package/dist/notice-bar/notice-bar.vue +175 -171
  115. package/dist/notice-bar/props.ts +2 -2
  116. package/dist/notice-bar/type.ts +1 -1
  117. package/dist/npm/dayjs/esm/locale/ar.js +81 -0
  118. package/dist/npm/dayjs/esm/locale/it.js +39 -0
  119. package/dist/overlay/overlay.vue +50 -48
  120. package/dist/picker/picker.vue +168 -161
  121. package/dist/picker-item/picker-item.vue +269 -269
  122. package/dist/popover/README.md +1 -1
  123. package/dist/popover/popover.vue +262 -261
  124. package/dist/popover/props.ts +4 -4
  125. package/dist/popover/type.ts +2 -2
  126. package/dist/popup/popup.vue +46 -45
  127. package/dist/progress/README.md +1 -1
  128. package/dist/progress/progress.vue +76 -76
  129. package/dist/pull-down-refresh/props.ts +2 -2
  130. package/dist/pull-down-refresh/pull-down-refresh.vue +240 -234
  131. package/dist/pull-down-refresh/type.ts +1 -1
  132. package/dist/qrcode/README.md +1 -1
  133. package/dist/qrcode/components/qrcode-canvas/qrcode-canvas.vue +340 -338
  134. package/dist/qrcode/components/qrcode-status/qrcode-status.vue +6 -6
  135. package/dist/qrcode/qrcode.vue +93 -87
  136. package/dist/radio/props.ts +6 -6
  137. package/dist/radio/radio.vue +118 -120
  138. package/dist/radio/type.ts +3 -3
  139. package/dist/radio-group/props.ts +4 -4
  140. package/dist/radio-group/radio-group.vue +136 -134
  141. package/dist/radio-group/type.ts +4 -4
  142. package/dist/rate/computed.js +2 -2
  143. package/dist/rate/props.ts +4 -4
  144. package/dist/rate/rate.vue +155 -154
  145. package/dist/rate/type.ts +2 -2
  146. package/dist/result/result.vue +41 -39
  147. package/dist/row/row.vue +38 -36
  148. package/dist/scroll-view/scroll-view.vue +24 -22
  149. package/dist/search/props.ts +2 -2
  150. package/dist/search/search.vue +127 -125
  151. package/dist/search/type.ts +1 -1
  152. package/dist/side-bar/side-bar.vue +57 -55
  153. package/dist/side-bar-item/side-bar-item.vue +86 -86
  154. package/dist/skeleton/skeleton.vue +126 -124
  155. package/dist/slider/README.md +1 -1
  156. package/dist/slider/props.ts +2 -2
  157. package/dist/slider/slider.vue +457 -457
  158. package/dist/slider/type.ts +1 -1
  159. package/dist/step-item/step-item.vue +77 -75
  160. package/dist/stepper/props.ts +2 -2
  161. package/dist/stepper/stepper.vue +168 -149
  162. package/dist/stepper/type.ts +1 -1
  163. package/dist/steps/props.ts +2 -2
  164. package/dist/steps/steps.vue +83 -81
  165. package/dist/steps/type.ts +1 -1
  166. package/dist/sticky/sticky.vue +104 -102
  167. package/dist/swipe-cell/swipe-cell.vue +91 -89
  168. package/dist/swiper/README.md +1 -1
  169. package/dist/swiper/swiper.vue +91 -89
  170. package/dist/swiper-nav/swiper-nav.vue +38 -36
  171. package/dist/switch/props.ts +2 -2
  172. package/dist/switch/switch.vue +62 -62
  173. package/dist/switch/type.ts +1 -1
  174. package/dist/tab-bar/tab-bar.vue +88 -86
  175. package/dist/tab-bar-item/tab-bar-item.vue +85 -82
  176. package/dist/tab-panel/tab-panel.vue +66 -64
  177. package/dist/tabs/tabs.vue +294 -287
  178. package/dist/tag/tag.vue +79 -77
  179. package/dist/textarea/props.ts +6 -6
  180. package/dist/textarea/textarea.vue +127 -126
  181. package/dist/textarea/type.ts +3 -3
  182. package/dist/toast/toast.vue +107 -106
  183. package/dist/transition/transition.vue +30 -28
  184. package/dist/tree-select/tree-select.vue +151 -151
  185. package/dist/types/config-provider.d.ts +7 -0
  186. package/dist/types/index.d.ts +2 -0
  187. package/dist/types/popover.d.ts +7 -0
  188. package/dist/upload/README.en-US.md +13 -14
  189. package/dist/upload/README.md +11 -12
  190. package/dist/upload/props.ts +2 -4
  191. package/dist/upload/type.ts +12 -11
  192. package/dist/upload/upload.css +1 -1
  193. package/dist/upload/upload.vue +672 -512
  194. package/dist/watermark/watermark.vue +151 -149
  195. package/global.d.ts +2 -0
  196. package/package.json +15 -3
  197. package/dist/form/form-item-props.ts +0 -56
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <view
3
- :style="tools._style([customStyle])"
3
+ :style="'' + tools._style([customStyle])"
4
4
  :class="classPrefix + ' ' + tClass"
5
5
  >
6
6
  <t-grid
@@ -38,7 +38,7 @@
38
38
  :shape="(imageProps && imageProps.shape) || 'round'"
39
39
  :webp="(imageProps && imageProps.webp) || false"
40
40
  :show-menu-by-longpress="(imageProps && imageProps.showMenuByLongpress) || false"
41
- @click="onPreview($event, { file, index })"
41
+ @click="(e) => onPreview(e, { file, index })"
42
42
  />
43
43
  <video
44
44
  v-if="file.type === 'video'"
@@ -66,7 +66,7 @@
66
66
  aria-hidden
67
67
  />
68
68
  <view :class="classPrefix + '__progress-text'">
69
- {{ file.percent ? file.percent + '%' : '上传中...' }}
69
+ {{ file.percent ? file.percent + '%' : globalConfig.progress.uploadingText }}
70
70
  </view>
71
71
  </block>
72
72
  <t-icon
@@ -79,7 +79,7 @@
79
79
  v-if="file.status == 'reload' || file.status == 'failed'"
80
80
  :class="classPrefix + '__progress-text'"
81
81
  >
82
- {{ file.status == 'reload' ? '重新上传' : '上传失败' }}
82
+ {{ file.status == 'reload' ? globalConfig.progress.reloadText : globalConfig.progress.failText }}
83
83
  </view>
84
84
  </view>
85
85
  <view
@@ -133,12 +133,12 @@
133
133
  v-for="(file, index) in customFiles"
134
134
  :key="index"
135
135
  :ref="classPrefix + '__drag-item'"
136
- :class="getDragItemClass(index)"
137
- :style="getDragItemStyle(index)"
136
+ :class="'' + getDragItemClass(index)"
137
+ :style="'' + getDragItemStyle(index)"
138
138
  :data-index="index"
139
- @longpress="parseEventDynamicCode($event, 'longPress', index)"
140
- @touchmove.stop.prevent="parseEventDynamicCode($event, dragging ? 'touchMove' : '', index)"
141
- @touchend.stop.prevent="parseEventDynamicCode($event, dragging ? 'touchEnd' : '', index)"
139
+ @longpress="(e) => parseEventDynamicCode(e, 'longPress', index)"
140
+ @touchmove.stop.prevent="(e) => parseEventDynamicCode(e, dragging ? 'touchMove' : '', index)"
141
+ @touchend.stop.prevent="(e) => parseEventDynamicCode(e, dragging ? 'touchEnd' : '', index)"
142
142
  >
143
143
  <t-grid-item
144
144
  :t-class="classPrefix + '__grid ' + classPrefix + '__grid-file'"
@@ -166,7 +166,7 @@
166
166
  :shape="(imageProps && imageProps.shape) || 'round'"
167
167
  :webp="(imageProps && imageProps.webp) || false"
168
168
  :show-menu-by-longpress="(imageProps && imageProps.showMenuByLongpress) || false"
169
- @click="onPreview($event, { file, index })"
169
+ @click="(e) => onPreview(e, { file, index })"
170
170
  />
171
171
  <video
172
172
  v-if="file.type === 'video'"
@@ -194,7 +194,7 @@
194
194
  aria-hidden
195
195
  />
196
196
  <view :class="classPrefix + '__progress-text'">
197
- {{ file.percent ? file.percent + '%' : '上传中...' }}
197
+ {{ file.percent ? file.percent + '%' : globalConfig.progress.uploadingText }}
198
198
  </view>
199
199
  </block>
200
200
  <t-icon
@@ -207,7 +207,7 @@
207
207
  v-if="file.status == 'reload' || file.status == 'failed'"
208
208
  :class="classPrefix + '__progress-text'"
209
209
  >
210
- {{ file.status == 'reload' ? '重新上传' : '上传失败' }}
210
+ {{ file.status == 'reload' ? globalConfig.progress.reloadText : globalConfig.progress.failText }}
211
211
  </view>
212
212
  </view>
213
213
  <view
@@ -231,8 +231,8 @@
231
231
  <view
232
232
  v-if="addBtn && customLimit > 0"
233
233
  :ref="classPrefix + '__drag-item'"
234
- :class="getDragItemClass(customFiles.length)"
235
- :style="getDragItemStyle(customFiles.length)"
234
+ :class="''+getDragItemClass(customFiles.length)"
235
+ :style="''+getDragItemStyle(customFiles.length)"
236
236
  >
237
237
  <t-grid-item
238
238
  :t-class="classPrefix + '__grid'"
@@ -288,7 +288,9 @@ import {
288
288
  import { parseEventDynamicCode } from '../common/event/dynamic';
289
289
 
290
290
 
291
- const name = `${prefix}-upload`;
291
+ import usingConfig from '../mixins/using-config';
292
+ const componentName = 'upload';
293
+ const name = `${prefix}-${componentName}`;
292
294
 
293
295
  const makeMethods = () => [
294
296
  [longPress, 'longPress'],
@@ -307,579 +309,737 @@ const makeMethods = () => [
307
309
  }, {});
308
310
 
309
311
 
310
- export default uniComponent({
311
- name,
312
- options: {
313
- styleIsolation: 'shared',
314
- },
315
- controlledProps: [
316
- {
317
- key: 'files',
318
- event: 'success',
319
- },
320
- ],
321
- externalClasses: [`${prefix}-class`],
312
+ export default {
322
313
  components: {
323
314
  TGrid,
324
315
  TGridItem,
325
316
  TIcon,
326
317
  TImage,
327
318
  },
328
- props: {
329
- ...props,
330
- },
331
- data() {
332
- return {
333
- classPrefix: name,
334
- prefix,
335
- current: false,
336
- proofs: [],
337
- customFiles: [], // 内部动态修改的files
338
- customLimit: 0, // 内部动态修改的limit
339
- column: 4,
340
- dragBaseData: {}, // 拖拽所需要页面数据
341
- rows: 0, // 行数
342
- dragWrapStyle: '', // 拖拽容器的样式
343
- dragList: [], // 拖拽的数据列
344
- dragging: true, // 是否开始拖拽
345
- dragLayout: false, // 是否开启拖拽布局
346
- tools,
347
-
348
- gridItemStyle: '',
349
-
350
- fakeState: {},
351
-
352
- dragItemClassList: [],
353
- dragItemStyleList: [],
354
- };
355
- },
356
- watch: {
357
- files: {
358
- handler() {
359
- this.onWatchFilesLimit();
360
- },
361
- deep: true,
319
+ ...uniComponent({
320
+ name,
321
+ mixins: [usingConfig({ componentName })],
322
+ options: {
323
+ styleIsolation: 'shared',
362
324
  },
363
- max: 'onWatchFilesLimit',
364
- draggable: {
365
- handler() {
366
- this.onWatchFilesLimit();
325
+ controlledProps: [
326
+ {
327
+ key: 'files',
328
+ event: 'success',
367
329
  },
368
- deep: true,
330
+ ],
331
+ externalClasses: [`${prefix}-class`],
332
+ props: {
333
+ ...props,
334
+ },
335
+ data() {
336
+ return {
337
+ classPrefix: name,
338
+ prefix,
339
+ current: false,
340
+ proofs: [],
341
+ customFiles: [], // 内部动态修改的files
342
+ customLimit: 0, // 内部动态修改的limit
343
+ column: 4,
344
+ dragBaseData: {}, // 拖拽所需要页面数据
345
+ rows: 0, // 行数
346
+ dragWrapStyle: '', // 拖拽容器的样式
347
+ dragList: [], // 拖拽的数据列
348
+ dragging: true, // 是否开始拖拽
349
+ dragLayout: false, // 是否开启拖拽布局
350
+ tools,
351
+
352
+ gridItemStyle: '',
353
+
354
+ fakeState: {},
355
+
356
+ dragItemClassList: [],
357
+ dragItemStyleList: [],
358
+ };
369
359
  },
360
+ watch: {
361
+ files: {
362
+ handler() {
363
+ this.onWatchFilesLimit();
364
+ },
365
+ deep: true,
366
+ },
367
+ max: 'onWatchFilesLimit',
368
+ draggable: {
369
+ handler() {
370
+ this.onWatchFilesLimit();
371
+ },
372
+ deep: true,
373
+ },
370
374
 
371
- gridConfig: {
372
- handler() {
373
- this.updateGrid();
375
+ gridConfig: {
376
+ handler() {
377
+ this.updateGrid();
378
+ },
379
+ deep: true,
374
380
  },
375
- deep: true,
376
- },
377
- dragList: {
378
- handler(val) {
379
- setTimeout(() => {
380
- this.listObserver(val);
381
- }, 33);
381
+ dragList: {
382
+ handler(val) {
383
+ setTimeout(() => {
384
+ this.listObserver(val);
385
+ }, 33);
386
+ },
387
+ deep: true,
388
+ immediate: true,
382
389
  },
383
- deep: true,
384
- immediate: true,
385
- },
386
- dragBaseData: {
387
- handler(val) {
388
- this.baseDataObserver(val);
390
+ dragBaseData: {
391
+ handler(val) {
392
+ this.baseDataObserver(val);
393
+ },
394
+ deep: true,
395
+ immediate: true,
389
396
  },
390
- deep: true,
391
- immediate: true,
392
397
  },
393
- },
394
- mounted() {
395
- this.handleLimit(this.files, this.max);
396
- this.updateGrid();
397
- },
398
- methods: {
399
- getWrapperAriaRole,
400
- getWrapperAriaLabel,
398
+ mounted() {
399
+ this.handleLimit(this.files, this.max);
400
+ this.updateGrid();
401
+ },
402
+ methods: {
403
+ getWrapperAriaRole,
404
+ getWrapperAriaLabel,
401
405
 
402
- ...makeMethods(),
406
+ ...makeMethods(),
403
407
 
404
- handleLimit(customFiles, max) {
405
- if (max === 0) {
406
- max = Number.MAX_SAFE_INTEGER;
407
- }
408
- this.customFiles = customFiles.length > max ? customFiles.slice(0, max) : customFiles;
409
- this.customLimit = max - customFiles.length;
410
- this.dragging = true;
408
+ handleLimit(customFiles, max) {
409
+ if (max === 0) {
410
+ max = Number.MAX_SAFE_INTEGER;
411
+ }
412
+ this.customFiles = customFiles.length > max ? customFiles.slice(0, max) : customFiles;
413
+ this.customLimit = max - customFiles.length;
414
+ this.dragging = true;
411
415
 
412
- this.initDragLayout();
413
- },
416
+ this.initDragLayout();
417
+ },
414
418
 
415
- triggerSuccessEvent(files) {
416
- this._trigger('success', { files: [...this.customFiles, ...files] });
417
- },
419
+ triggerSuccessEvent(files) {
420
+ this._trigger('success', { files: [...this.customFiles, ...files] });
421
+ },
418
422
 
419
- triggerFailEvent(err) {
420
- this.$emit('fail', err);
421
- },
423
+ triggerFailEvent(err) {
424
+ this.$emit('fail', err);
425
+ },
422
426
 
423
- onFileClick(e) {
424
- const { file, index } = e.currentTarget.dataset;
425
- this.$emit('click', { index, file });
426
- },
427
+ onFileClick(e) {
428
+ const { file, index } = e.currentTarget.dataset;
429
+ this.$emit('click', { index, file });
430
+ },
427
431
 
428
- /**
432
+ /**
429
433
  * 由于小程序暂时在ios上不支持返回上传文件的fileType,这里用文件的后缀来判断
430
434
  * @param mediaType
431
435
  * @param tempFilePath
432
436
  * @returns string
433
437
  * @link https://developers.weixin.qq.com/community/develop/doc/00042820b28ee8fb41fc4d0c254c00
434
438
  */
435
- getFileType(mediaType, tempFilePath, fileType) {
436
- if (fileType) return fileType; // 如果有返回fileType就直接用
437
- if (mediaType.length === 1) {
438
- // 在单选媒体类型的时候直接使用单选媒体类型
439
- return mediaType[0];
440
- }
441
- // 否则根据文件后缀进行判读
442
- const videoType = ['avi', 'wmv', 'mkv', 'mp4', 'mov', 'rm', '3gp', 'flv', 'mpg', 'rmvb'];
443
- const temp = tempFilePath.split('.');
444
- const postfix = temp[temp.length - 1];
445
- if (videoType.includes(postfix.toLocaleLowerCase())) {
446
- return 'video';
447
- }
448
- return 'image';
449
- },
439
+ getFileType(mediaType, tempFilePath, fileType) {
440
+ if (fileType) return fileType; // 如果有返回fileType就直接用
441
+ if (mediaType.length === 1) {
442
+ // 在单选媒体类型的时候直接使用单选媒体类型
443
+ return mediaType[0];
444
+ }
445
+ // 否则根据文件后缀进行判读
446
+ const videoType = ['avi', 'wmv', 'mkv', 'mp4', 'mov', 'rm', '3gp', 'flv', 'mpg', 'rmvb'];
447
+ const temp = tempFilePath.split('.');
448
+ const postfix = temp[temp.length - 1];
449
+ if (videoType.includes(postfix.toLocaleLowerCase())) {
450
+ return 'video';
451
+ }
452
+ return 'image';
453
+ },
450
454
 
451
- // 选中文件之后,计算一个随机的短文件名
452
- getRandFileName(filePath) {
453
- const extIndex = filePath.lastIndexOf('.');
454
- const extName = extIndex === -1 ? '' : filePath.substr(extIndex);
455
- return parseInt(`${Date.now()}${Math.floor(Math.random() * 900 + 100)}`, 10).toString(36) + extName;
456
- },
455
+ // 选中文件之后,计算一个随机的短文件名
456
+ getRandFileName(filePath) {
457
+ const extIndex = filePath.lastIndexOf('.');
458
+ const extName = extIndex === -1 ? '' : filePath.substr(extIndex);
459
+ return parseInt(`${Date.now()}${Math.floor(Math.random() * 900 + 100)}`, 10).toString(36) + extName;
460
+ },
457
461
 
458
- checkFileSize(size, sizeLimit, fileType) {
459
- if (isOverSize(size, sizeLimit)) {
460
- let title = `${fileType === 'video' ? '视频' : '图片'}大小超过限制`;
462
+ checkFileSize(size, sizeLimit, fileType) {
463
+ if (isOverSize(size, sizeLimit)) {
464
+ let title = `${fileType === 'video' ? '视频' : '图片'}大小超过限制`;
461
465
 
462
- if (isObject(sizeLimit)) {
463
- const { size: limitSize, message: limitMessage } = sizeLimit;
464
- title = limitMessage?.replace('{sizeLimit}', String(limitSize));
466
+ if (isObject(sizeLimit)) {
467
+ const { size: limitSize, message: limitMessage } = sizeLimit;
468
+ title = limitMessage?.replace('{sizeLimit}', String(limitSize));
469
+ }
470
+ uni.showToast({ icon: 'none', title });
471
+ return true;
465
472
  }
466
- uni.showToast({ icon: 'none', title });
467
- return true;
468
- }
469
- return false;
470
- },
473
+ return false;
474
+ },
471
475
 
472
- onDelete(e) {
473
- const { index } = e.currentTarget.dataset;
474
- this.deleteHandle(index);
475
- },
476
+ onDelete(e) {
477
+ const { index } = e.currentTarget.dataset;
478
+ this.deleteHandle(index);
479
+ },
476
480
 
477
- deleteHandle(index) {
478
- const { customFiles } = this;
479
- const delFile = customFiles[index];
480
- this.$emit('remove', { index, file: delFile });
481
- },
481
+ deleteHandle(index) {
482
+ const { customFiles } = this;
483
+ const delFile = customFiles[index];
484
+ this.$emit('remove', { index, file: delFile });
485
+ },
482
486
 
483
- updateGrid() {
484
- let { gridConfig = {} } = this;
485
- if (!isObject(gridConfig)) gridConfig = {};
486
- const { column = 4, width = 160, height = 160 } = gridConfig;
487
+ updateGrid() {
488
+ let { gridConfig = {} } = this;
489
+ if (!isObject(gridConfig)) gridConfig = {};
490
+ const { column = 4, width = 160, height = 160 } = gridConfig;
487
491
 
488
- this.gridItemStyle = `width:${width}rpx;height:${height}rpx`;
489
- this.column = column;
490
- },
492
+ this.gridItemStyle = `width:${width}rpx;height:${height}rpx`;
493
+ this.column = column;
494
+ },
491
495
 
492
- resetDragLayout() {
493
- this.dragBaseData = {};
494
- this.dragWrapStyle = '';
495
- this.dragLayout = false;
496
- },
496
+ resetDragLayout() {
497
+ this.dragBaseData = {};
498
+ this.dragWrapStyle = '';
499
+ this.dragLayout = false;
500
+ },
497
501
 
498
- initDragLayout() {
499
- const { draggable, disabled, customFiles } = this;
500
- if (!draggable || disabled || customFiles.length === 0) {
501
- this.resetDragLayout();
502
- return;
503
- }
504
- this.initDragList();
505
- setTimeout(() => {
506
- this.initDragBaseData();
507
- }, 33)
508
- ;
509
- },
502
+ initDragLayout() {
503
+ const { draggable, disabled, customFiles } = this;
504
+ if (!draggable || disabled || customFiles.length === 0) {
505
+ this.resetDragLayout();
506
+ return;
507
+ }
508
+ this.initDragList();
509
+ setTimeout(() => {
510
+ this.initDragBaseData();
511
+ }, 33)
512
+ ;
513
+ },
510
514
 
511
- initDragList() {
512
- let i = 0;
513
- const { column, customFiles, customLimit } = this;
514
- const dragList = [];
515
- customFiles.forEach((item, index) => {
516
- dragList.push({
517
- realKey: i, // 真实顺序
518
- sortKey: index, // 整体顺序
519
- tranX: `${(index % column) * 100}%`,
520
- tranY: `${Math.floor(index / column) * 100}%`,
521
- data: { ...item },
522
- });
523
- i += 1;
524
- });
525
- if (customLimit > 0) {
526
- const listLength = dragList.length;
527
- dragList.push({
528
- realKey: listLength, // 真实顺序
529
- sortKey: listLength, // 整体顺序
530
- tranX: `${(listLength % column) * 100}%`,
531
- tranY: `${Math.floor(listLength / column) * 100}%`,
532
- fixed: true,
515
+ initDragList() {
516
+ let i = 0;
517
+ const { column, customFiles, customLimit } = this;
518
+ const dragList = [];
519
+ customFiles.forEach((item, index) => {
520
+ dragList.push({
521
+ realKey: i, // 真实顺序
522
+ sortKey: index, // 整体顺序
523
+ tranX: `${(index % column) * 100}%`,
524
+ tranY: `${Math.floor(index / column) * 100}%`,
525
+ data: { ...item },
526
+ });
527
+ i += 1;
533
528
  });
534
- }
535
- this.rows = Math.ceil(dragList.length / column);
536
-
537
- this.dragList = dragList;
538
- },
539
-
540
- initDragBaseData() {
541
- const { classPrefix, rows, column } = this;
529
+ if (customLimit > 0) {
530
+ const listLength = dragList.length;
531
+ dragList.push({
532
+ realKey: listLength, // 真实顺序
533
+ sortKey: listLength, // 整体顺序
534
+ tranX: `${(listLength % column) * 100}%`,
535
+ tranY: `${Math.floor(listLength / column) * 100}%`,
536
+ fixed: true,
537
+ });
538
+ }
539
+ this.rows = Math.ceil(dragList.length / column);
542
540
 
543
- let query;
544
- // #ifdef H5 || APP-PLUS
545
- query = uni.createSelectorQuery().in(this);
546
- // #endif
547
- if (!query) {
548
- query = this.createSelectorQuery();
549
- }
541
+ this.dragList = dragList;
542
+ },
550
543
 
544
+ initDragBaseData() {
545
+ const { classPrefix, rows, column } = this;
551
546
 
552
- let selectorGridItem;
553
- let selectorGrid;
554
- // #ifdef H5 || APP-PLUS
555
- selectorGridItem = '.t-grid-item';
556
- selectorGrid = '.t-grid';
557
- // #endif
547
+ let query;
548
+ // #ifdef H5 || APP-PLUS
549
+ query = uni.createSelectorQuery().in(this);
550
+ // #endif
551
+ if (!query) {
552
+ query = this.createSelectorQuery();
553
+ }
558
554
 
559
- if (!selectorGridItem) {
560
- selectorGridItem = `.${classPrefix} >>> .t-grid-item`;
561
- selectorGrid = `.${classPrefix} >>> .t-grid`;
562
- }
563
-
564
- query.select(selectorGridItem).boundingClientRect();
565
- query.select(selectorGrid).boundingClientRect();
566
- query.selectViewport().scrollOffset();
567
- query.exec((res) => {
568
- const [{ width, height }, { left, top }, { scrollTop }] = res;
569
- const dragBaseData = {
570
- rows,
571
- classPrefix,
572
- itemWidth: width,
573
- itemHeight: height,
574
- wrapLeft: left,
575
- wrapTop: top + scrollTop,
576
- columns: column,
577
- };
578
- const dragWrapStyle = `height: ${rows * height}px`;
579
555
 
580
- this.dragBaseData = dragBaseData;
581
- this.dragWrapStyle = dragWrapStyle;
582
- this.dragLayout = true;
556
+ let selectorGridItem;
557
+ let selectorGrid;
558
+ // #ifdef H5 || APP-PLUS
559
+ selectorGridItem = '.t-grid-item';
560
+ selectorGrid = '.t-grid';
561
+ // #endif
583
562
 
563
+ if (!selectorGridItem) {
564
+ selectorGridItem = `.${classPrefix} >>> .t-grid-item`;
565
+ selectorGrid = `.${classPrefix} >>> .t-grid`;
566
+ }
584
567
 
585
- // 为了给拖拽元素加上拖拽方法,同时控制不拖拽时不取消穿透
586
- const timer = setTimeout(() => {
587
- this.dragging = false;
588
- clearTimeout(timer);
589
- }, 0);
590
- });
591
- },
568
+ query.select(selectorGridItem).boundingClientRect();
569
+ query.select(selectorGrid).boundingClientRect();
570
+ query.selectViewport().scrollOffset();
571
+ query.exec((res) => {
572
+ const [{ width, height }, { left, top }, { scrollTop }] = res;
573
+ const dragBaseData = {
574
+ rows,
575
+ classPrefix,
576
+ itemWidth: width,
577
+ itemHeight: height,
578
+ wrapLeft: left,
579
+ wrapTop: top + scrollTop,
580
+ columns: column,
581
+ };
582
+ const dragWrapStyle = `height: ${rows * height}px`;
583
+
584
+ this.dragBaseData = dragBaseData;
585
+ this.dragWrapStyle = dragWrapStyle;
586
+ this.dragLayout = true;
587
+
588
+
589
+ // 为了给拖拽元素加上拖拽方法,同时控制不拖拽时不取消穿透
590
+ const timer = setTimeout(() => {
591
+ this.dragging = false;
592
+ clearTimeout(timer);
593
+ }, 0);
594
+ });
595
+ },
592
596
 
593
- getPreviewMediaSources() {
594
- const previewMediaSources = [];
595
- this.customFiles.forEach((ele) => {
596
- const mediaSource = {
597
- url: ele.url,
598
- type: ele.type,
599
- poster: ele.thumb || undefined,
600
- };
601
- previewMediaSources.push(mediaSource);
602
- });
597
+ getPreviewMediaSources() {
598
+ const previewMediaSources = [];
599
+ this.customFiles.forEach((ele) => {
600
+ const mediaSource = {
601
+ url: ele.url,
602
+ type: ele.type,
603
+ poster: ele.thumb || undefined,
604
+ };
605
+ previewMediaSources.push(mediaSource);
606
+ });
603
607
 
604
- return previewMediaSources;
605
- },
608
+ return previewMediaSources;
609
+ },
606
610
 
607
- onPreview(e) {
608
- this.onFileClick(e);
609
- const { preview } = this;
611
+ onPreview(e) {
612
+ this.onFileClick(e);
613
+ const { preview } = this;
610
614
 
611
- if (!preview) return;
615
+ if (!preview) return;
612
616
 
613
- const usePreviewMedia = this.customFiles.some(file => file.type === 'video');
614
- if (usePreviewMedia) {
615
- this.onPreviewMedia(e);
616
- } else {
617
- this.onPreviewImage(e);
618
- }
619
- },
617
+ const usePreviewMedia = this.customFiles.some(file => file.type === 'video');
618
+ if (usePreviewMedia) {
619
+ this.onPreviewMedia(e);
620
+ } else {
621
+ this.onPreviewImage(e);
622
+ }
623
+ },
620
624
 
621
- onPreviewImage(e) {
622
- const { index } = e.currentTarget.dataset;
623
- const urls = this.customFiles.filter(file => file.percent !== -1).map(file => file.url);
624
- const current = this.customFiles[index]?.url;
625
- uni.previewImage({
626
- urls,
627
- current,
628
- fail() {
629
- uni.showToast({ title: '预览图片失败', icon: 'none' });
630
- },
631
- });
632
- },
625
+ onPreviewImage(e) {
626
+ const { index } = e.currentTarget.dataset;
627
+ const urls = this.customFiles.filter(file => file.percent !== -1).map(file => file.url);
628
+ const current = this.customFiles[index]?.url;
629
+ uni.previewImage({
630
+ urls,
631
+ current,
632
+ fail() {
633
+ uni.showToast({ title: '预览图片失败', icon: 'none' });
634
+ },
635
+ });
636
+ },
633
637
 
634
- onPreviewMedia(e) {
635
- const { index: current } = e.currentTarget.dataset;
636
- const sources = this.getPreviewMediaSources();
637
- uni.previewMedia({
638
- sources,
639
- current,
640
- fail() {
641
- uni.showToast({ title: '预览视频失败', icon: 'none' });
642
- },
643
- });
644
- },
638
+ onPreviewMedia(e) {
639
+ const { index: current } = e.currentTarget.dataset;
640
+ const sources = this.getPreviewMediaSources();
641
+ uni.previewMedia({
642
+ sources,
643
+ current,
644
+ fail() {
645
+ uni.showToast({ title: '预览视频失败', icon: 'none' });
646
+ },
647
+ });
648
+ },
645
649
 
646
- uploadFiles(files) {
647
- return Promise.resolve().then(() => {
650
+ uploadFiles(files) {
651
+ return Promise.resolve().then(() => {
648
652
  // 开始调用上传函数
649
- const task = this.data.requestMethod(files);
650
- if (task instanceof Promise) {
651
- return task;
652
- }
653
- return Promise.resolve({});
654
- });
655
- },
653
+ const task = this.requestMethod(files);
654
+ if (task instanceof Promise) {
655
+ return task;
656
+ }
657
+ return Promise.resolve({});
658
+ });
659
+ },
656
660
 
657
- startUpload(files) {
661
+ startUpload(files) {
658
662
  // 如果传入了上传函数,则进度设为0并开始上传,否则跳过上传
659
- if (typeof this.requestMethod === 'function') {
660
- return this.uploadFiles(files)
661
- .then(() => {
662
- files.forEach((file) => {
663
- file.percent = 100;
663
+ if (typeof this.requestMethod === 'function') {
664
+ return this.uploadFiles(files)
665
+ .then(() => {
666
+ files.forEach((file) => {
667
+ file.percent = 100;
668
+ });
669
+ this.triggerSuccessEvent(files);
670
+ })
671
+ .catch((err) => {
672
+ this.triggerFailEvent(err);
664
673
  });
665
- this.triggerSuccessEvent(files);
666
- })
667
- .catch((err) => {
668
- this.triggerFailEvent(err);
669
- });
670
- }
674
+ }
671
675
 
672
- // 如果没有上传函数,success事件与微信api上传成功关联
673
- this.triggerSuccessEvent(files);
676
+ // 如果没有上传函数,success事件与微信api上传成功关联
677
+ this.triggerSuccessEvent(files);
674
678
 
675
- this.handleLimit(this.customFiles, this.max);
676
- return Promise.resolve();
677
- },
679
+ this.handleLimit(this.customFiles, this.max);
680
+ return Promise.resolve();
681
+ },
678
682
 
679
- onWatchFilesLimit() {
680
- this.handleLimit(this.files, this.max);
681
- },
683
+ onWatchFilesLimit() {
684
+ this.handleLimit(this.files, this.max);
685
+ },
682
686
 
683
- onAddTap() {
684
- const { disabled, mediaType, source } = this;
685
- if (disabled) return;
686
- if (source === 'media') {
687
- this.chooseMedia(mediaType);
688
- } else {
689
- this.chooseMessageFile(mediaType);
690
- }
691
- },
687
+ onAddTap() {
688
+ const { disabled, mediaType, source } = this;
689
+ if (disabled) return;
690
+ if (source === 'media') {
691
+ this.chooseMedia(mediaType);
692
+ } else {
693
+ this.chooseMessageFile(mediaType);
694
+ }
695
+ },
692
696
 
693
- chooseMedia(mediaType) {
694
- const { customLimit } = this;
695
- const { config, sizeLimit } = this;
696
- let func = 'chooseMedia';
697
- // #ifdef H5 || MP-ALIPAY
698
- func = 'chooseImage';
699
- // #endif
700
- // #ifdef MP-WEIXIN
701
- if (isPC || isWxWork) {
702
- func = 'chooseImage';
703
- }
704
- // #endif
705
- uni[func]({
706
- count: Math.min(20, customLimit),
707
- mediaType,
708
- ...config,
709
- success: (res) => {
710
- const files = [];
697
+ chooseMedia(mediaType) {
698
+ const { customLimit } = this;
699
+ const { config, sizeLimit } = this;
711
700
 
712
- // 支持单/多文件
713
- res.tempFiles.forEach((temp) => {
714
- const { size, fileType, tempFilePath, width, height, duration, thumbTempFilePath, ...res } = temp;
715
-
716
- if (this.checkFileSize(size, sizeLimit, fileType)) return;
717
-
718
-
719
- const name = temp.name || this.getRandFileName(tempFilePath);
720
- files.push({
721
- name,
722
- type: this.getFileType(mediaType, temp.name || tempFilePath, fileType),
723
- url: tempFilePath,
724
- size,
725
- width,
726
- height,
727
- duration,
728
- thumb: thumbTempFilePath,
729
- percent: 0,
730
- ...res,
731
- });
732
- });
733
- this.afterSelect(files);
734
- },
735
- fail: (err) => {
736
- this.triggerFailEvent(err);
737
- },
738
- complete: (res) => {
739
- this.$emit('complete', res);
740
- },
741
- });
742
- },
701
+ let parsed = false;
743
702
 
744
- chooseMessageFile(mediaType) {
745
- const { customLimit } = this;
746
- const { config, sizeLimit } = this;
747
- uni.chooseMessageFile({
748
- count: Math.min(100, customLimit),
749
- type: Array.isArray(mediaType) ? 'all' : mediaType,
750
- ...config,
751
- success: (res) => {
752
- const files = [];
753
-
754
- // 支持单/多文件
755
- res.tempFiles.forEach((temp) => {
756
- const { size, type: fileType, path: tempFilePath, ...res } = temp;
703
+ // #ifdef H5
704
+ this.chooseFileH5(mediaType, customLimit, sizeLimit);
705
+ parsed = true;
706
+ // #endif
757
707
 
758
- if (this.checkFileSize(size, sizeLimit, fileType)) return;
708
+ if (parsed) {
709
+ return;
710
+ }
759
711
 
760
- const name = this.getRandFileName(tempFilePath);
761
- files.push({
762
- name,
763
- type: this.getFileType(mediaType, tempFilePath, fileType),
764
- url: tempFilePath,
765
- size,
766
- percent: 0,
767
- ...res,
712
+ let func = 'chooseMedia';
713
+ // #ifdef MP-ALIPAY
714
+ func = 'chooseImage';
715
+ // #endif
716
+ // #ifdef MP-WEIXIN
717
+ if (isPC || isWxWork) {
718
+ func = 'chooseImage';
719
+ }
720
+ // #endif
721
+ uni[func]({
722
+ count: Math.min(20, customLimit),
723
+ mediaType,
724
+ ...config,
725
+ success: (res) => {
726
+ const files = [];
727
+
728
+ // 支持单/多文件
729
+ res.tempFiles.forEach((temp) => {
730
+ const { size, fileType, tempFilePath: tTempFilePath, path: tPath, width, height, duration, thumbTempFilePath, ...res } = temp;
731
+ const tempFilePath = tTempFilePath || tPath;
732
+ if (this.checkFileSize(size, sizeLimit, fileType)) return;
733
+
734
+ const name = temp.name || this.getRandFileName(tempFilePath);
735
+ files.push({
736
+ name,
737
+ type: this.getFileType(mediaType, temp.name || tempFilePath, fileType),
738
+ url: tempFilePath,
739
+ size,
740
+ width,
741
+ height,
742
+ duration,
743
+ thumb: thumbTempFilePath,
744
+ percent: 0,
745
+ ...res,
746
+ });
768
747
  });
748
+ this.afterSelect(files);
749
+ },
750
+ fail: (err) => {
751
+ this.triggerFailEvent(err);
752
+ },
753
+ complete: (res) => {
754
+ this.$emit('complete', res);
755
+ },
756
+ });
757
+ },
758
+
759
+ // #ifdef H5
760
+ /**
761
+ * H5 平台使用原生 input[type=file] 选择文件,支持图片和视频
762
+ */
763
+ chooseFileH5(mediaType, customLimit, sizeLimit) {
764
+ const input = document.createElement('input');
765
+ input.type = 'file';
766
+
767
+ // 根据 mediaType 生成 accept
768
+ const acceptTypes = [];
769
+ if (mediaType.includes('image')) acceptTypes.push('image/*');
770
+ if (mediaType.includes('video')) acceptTypes.push('video/*');
771
+ input.accept = acceptTypes.join(',') || 'image/*,video/*';
772
+
773
+ if (customLimit > 1) {
774
+ input.multiple = true;
775
+ }
776
+
777
+ input.onchange = (e) => {
778
+ const selectedFiles = Array.from(e.target.files || []);
779
+ if (selectedFiles.length === 0) {
780
+ this.$emit('complete', {});
781
+ return;
782
+ }
783
+
784
+ // 限制数量
785
+ const limitedFiles = selectedFiles.slice(0, Math.min(20, customLimit));
786
+ const files = [];
787
+ let processed = 0;
788
+
789
+ limitedFiles.forEach((file) => {
790
+ const fileType = file.type.startsWith('video/') ? 'video' : 'image';
791
+
792
+ if (this.checkFileSize(file.size, sizeLimit, fileType)) {
793
+ processed += 1;
794
+ if (processed === limitedFiles.length) {
795
+ this.afterSelect(files);
796
+ this.$emit('complete', {});
797
+ }
798
+ return;
799
+ }
800
+
801
+ const url = URL.createObjectURL(file);
802
+ const name = file.name || this.getRandFileName(url);
803
+
804
+ if (fileType === 'image') {
805
+ // 图片:获取宽高
806
+ const img = new Image();
807
+ img.onload = () => {
808
+ files.push({
809
+ name,
810
+ type: 'image',
811
+ url,
812
+ size: file.size,
813
+ width: img.width,
814
+ height: img.height,
815
+ percent: 0,
816
+ });
817
+ processed += 1;
818
+ if (processed === limitedFiles.length) {
819
+ this.afterSelect(files);
820
+ this.$emit('complete', {});
821
+ }
822
+ };
823
+ img.onerror = () => {
824
+ files.push({
825
+ name,
826
+ type: 'image',
827
+ url,
828
+ size: file.size,
829
+ percent: 0,
830
+ });
831
+ processed += 1;
832
+ if (processed === limitedFiles.length) {
833
+ this.afterSelect(files);
834
+ this.$emit('complete', {});
835
+ }
836
+ };
837
+ img.src = url;
838
+ } else {
839
+ // 视频:获取时长、宽高和封面
840
+ const video = document.createElement('video');
841
+ video.preload = 'metadata';
842
+ video.onloadedmetadata = () => {
843
+ const { duration } = video;
844
+ const width = video.videoWidth;
845
+ const height = video.videoHeight;
846
+
847
+ // 尝试截取第一帧作为封面
848
+ video.currentTime = 0.1;
849
+ video.onseeked = () => {
850
+ let thumb = '';
851
+ try {
852
+ const canvas = document.createElement('canvas');
853
+ canvas.width = width;
854
+ canvas.height = height;
855
+ canvas.getContext('2d').drawImage(video, 0, 0, width, height);
856
+ thumb = canvas.toDataURL('image/jpeg', 0.7);
857
+ } catch (err) {
858
+ // 跨域等情况下可能截图失败,忽略
859
+ }
860
+
861
+ files.push({
862
+ name,
863
+ type: 'video',
864
+ url,
865
+ size: file.size,
866
+ width,
867
+ height,
868
+ duration: Math.round(duration),
869
+ thumb,
870
+ percent: 0,
871
+ });
872
+ processed += 1;
873
+ if (processed === limitedFiles.length) {
874
+ this.afterSelect(files);
875
+ this.$emit('complete', {});
876
+ }
877
+ URL.revokeObjectURL(video.src);
878
+ };
879
+ };
880
+ video.onerror = () => {
881
+ files.push({
882
+ name,
883
+ type: 'video',
884
+ url,
885
+ size: file.size,
886
+ percent: 0,
887
+ });
888
+ processed += 1;
889
+ if (processed === limitedFiles.length) {
890
+ this.afterSelect(files);
891
+ this.$emit('complete', {});
892
+ }
893
+ };
894
+ video.src = url;
895
+ }
769
896
  });
770
- this.afterSelect(files);
771
- },
772
- fail: err => this.triggerFailEvent(err),
773
- complete: res => this.$emit('complete', res),
774
- });
775
- },
897
+ };
776
898
 
777
- afterSelect(files) {
778
- this._trigger('select-change', {
779
- files: [...this.customFiles],
780
- currentSelectedFiles: [files],
781
- });
782
- this._trigger('add', { files });
783
- this.startUpload(files);
784
- },
899
+ input.click();
900
+ },
901
+ // #endif
785
902
 
786
- dragVibrate(e) {
787
- const { vibrateType } = e;
788
- const { draggable } = this;
789
- const dragVibrate = coalesce(draggable?.vibrate, true);
790
- const dragCollisionVibrate = draggable?.collisionVibrate;
791
- if ((dragVibrate && vibrateType === 'longPress') || (dragCollisionVibrate && vibrateType === 'touchMove')) {
792
- uni.vibrateShort({
793
- type: 'light',
903
+ chooseMessageFile(mediaType) {
904
+ const { customLimit } = this;
905
+ const { config, sizeLimit } = this;
906
+ uni.chooseMessageFile({
907
+ count: Math.min(100, customLimit),
908
+ type: Array.isArray(mediaType) ? 'all' : mediaType,
909
+ ...config,
910
+ success: (res) => {
911
+ const files = [];
912
+
913
+ // 支持单/多文件
914
+ res.tempFiles.forEach((temp) => {
915
+ const { size, type: fileType, path: tempFilePath, ...res } = temp;
916
+
917
+ if (this.checkFileSize(size, sizeLimit, fileType)) return;
918
+
919
+ const name = this.getRandFileName(tempFilePath);
920
+ files.push({
921
+ name,
922
+ type: this.getFileType(mediaType, tempFilePath, fileType),
923
+ url: tempFilePath,
924
+ size,
925
+ percent: 0,
926
+ ...res,
927
+ });
928
+ });
929
+ this.afterSelect(files);
930
+ },
931
+ fail: err => this.triggerFailEvent(err),
932
+ complete: res => this.$emit('complete', res),
794
933
  });
795
- }
796
- },
934
+ },
797
935
 
798
- dragStatusChange(e) {
799
- const { dragging } = e;
800
- this.dragging = dragging;
801
- },
936
+ afterSelect(files) {
937
+ this._trigger('select-change', {
938
+ files: [...this.customFiles],
939
+ currentSelectedFiles: [files],
940
+ });
941
+ this._trigger('add', { files });
942
+ this.startUpload(files);
943
+ },
802
944
 
803
- dragEnd(e) {
804
- const { dragCollisionList } = e;
805
- let files = [];
806
- if (dragCollisionList.length === 0) {
807
- files = this.customFiles;
808
- } else {
809
- files = dragCollisionList.reduce((list, item) => {
810
- const { realKey, data, fixed } = item;
811
- if (!fixed) {
812
- list[realKey] = {
813
- ...data,
814
- };
815
- }
816
- return list;
817
- }, []);
818
- }
819
- this.triggerDropEvent(files);
820
- },
945
+ dragVibrate(e) {
946
+ const { vibrateType } = e;
947
+ const { draggable } = this;
948
+ const dragVibrate = coalesce(draggable?.vibrate, true);
949
+ const dragCollisionVibrate = draggable?.collisionVibrate;
950
+ if ((dragVibrate && vibrateType === 'longPress') || (dragCollisionVibrate && vibrateType === 'touchMove')) {
951
+ uni.vibrateShort({
952
+ type: 'light',
953
+ });
954
+ }
955
+ },
956
+
957
+ dragStatusChange(e) {
958
+ const { dragging } = e;
959
+ this.dragging = dragging;
960
+ },
961
+
962
+ dragEnd(e) {
963
+ const { dragCollisionList } = e;
964
+ let files = [];
965
+ if (dragCollisionList.length === 0) {
966
+ files = this.customFiles;
967
+ } else {
968
+ files = dragCollisionList.reduce((list, item) => {
969
+ const { realKey, data, fixed } = item;
970
+ if (!fixed) {
971
+ list[realKey] = {
972
+ ...data,
973
+ };
974
+ }
975
+ return list;
976
+ }, []);
977
+ }
978
+ this.triggerDropEvent(files);
979
+ },
821
980
 
822
- triggerDropEvent(files) {
823
- const { transition } = this;
824
- if (transition.backTransition) {
825
- const timer = setTimeout(() => {
981
+ triggerDropEvent(files) {
982
+ const { transition } = this;
983
+ if (transition.backTransition) {
984
+ const timer = setTimeout(() => {
985
+ this.$emit('drop', { files });
986
+ clearTimeout(timer);
987
+ }, transition.duration);
988
+ } else {
826
989
  this.$emit('drop', { files });
827
- clearTimeout(timer);
828
- }, transition.duration);
829
- } else {
830
- this.$emit('drop', { files });
831
- }
832
- },
833
- getState() {
834
- return this.fakeState || {};
835
- },
836
- callMethod(...args) {
837
- return this[args[0]]?.(...args.slice(1));
838
- },
839
- parseEventDynamicCode,
840
- setDragItemClass(index, operation, val) {
841
- if (!this.dragItemClassList[index]) {
842
- this.dragItemClassList[index] = [];
843
- }
844
- const valList = Array.isArray(val) ? val : [val];
845
- if (operation === 'add') {
846
- this.dragItemClassList[index].push(...valList);
847
- return;
848
- }
849
- if (operation === 'remove') {
850
- this.dragItemClassList[index] = this.dragItemClassList[index].filter(item => !valList.includes(item));
851
- }
852
- },
853
- getDragItemClass(index) {
854
- const { classPrefix } = this;
855
- const base = [
856
- `${classPrefix}__drag-item`,
857
- ];
858
- return [
859
- ...base,
860
- ...(this.dragItemClassList[index] || []),
861
- ].join(' ');
862
- },
863
- setDragItemStyle(index, val) {
864
- if (!this.dragItemStyleList[index]) {
865
- this.dragItemStyleList[index] = [];
866
- }
867
- this.dragItemStyleList[index].push(val);
868
- },
869
- getDragItemStyle(index) {
870
- const { column, transition } = this;
871
- const base = [
872
- `width: ${100 / column}%`,
873
- `--td-upload-drag-transition-duration: ${transition.duration}ms`,
874
- `--td-upload-drag-transition-timing-function: ${transition.timingFunction}`,
875
- ];
876
-
877
- return [
878
- ...base,
879
- ...(this.dragItemStyleList[index] || []),
880
- ].join(';');
990
+ }
991
+ },
992
+ getState() {
993
+ return this.fakeState || {};
994
+ },
995
+ callMethod(...args) {
996
+ return this[args[0]]?.(...args.slice(1));
997
+ },
998
+ parseEventDynamicCode,
999
+ setDragItemClass(index, operation, val) {
1000
+ if (!this.dragItemClassList[index]) {
1001
+ this.dragItemClassList[index] = [];
1002
+ }
1003
+ const valList = Array.isArray(val) ? val : [val];
1004
+ if (operation === 'add') {
1005
+ this.dragItemClassList[index].push(...valList);
1006
+ return;
1007
+ }
1008
+ if (operation === 'remove') {
1009
+ this.dragItemClassList[index] = this.dragItemClassList[index].filter(item => !valList.includes(item));
1010
+ }
1011
+ },
1012
+ getDragItemClass(index) {
1013
+ const { classPrefix } = this;
1014
+ const base = [
1015
+ `${classPrefix}__drag-item`,
1016
+ ];
1017
+ return [
1018
+ ...base,
1019
+ ...(this.dragItemClassList[index] || []),
1020
+ ].join(' ');
1021
+ },
1022
+ setDragItemStyle(index, val) {
1023
+ if (!this.dragItemStyleList[index]) {
1024
+ this.dragItemStyleList[index] = [];
1025
+ }
1026
+ this.dragItemStyleList[index].push(val);
1027
+ },
1028
+ getDragItemStyle(index) {
1029
+ const { column, transition } = this;
1030
+ const base = [
1031
+ `width: ${100 / column}%`,
1032
+ `--td-upload-drag-transition-duration: ${transition.duration}ms`,
1033
+ `--td-upload-drag-transition-timing-function: ${transition.timingFunction}`,
1034
+ ];
1035
+
1036
+ return [
1037
+ ...base,
1038
+ ...(this.dragItemStyleList[index] || []),
1039
+ ].join(';');
1040
+ },
881
1041
  },
882
- },
883
- });
1042
+ }),
1043
+ };
884
1044
  </script>
885
1045
  <style scoped src="./upload.css"></style>