Browse Source

fix: 组件 Uploader H5 打包去掉 Taro 内容 (#1895)

* fix: 修复 ImagePreview 在Taro编译成H5后报错的问题

* fix: 地址关闭时, Close 事件触发两次问题解决

* feat: 组件DatePicker 添加双向绑定

* docs: 组件Picker文档修改

* feat: 组件Picker与DatePicker新增属性safe-area-inset-bottom

* feat: imagepreview

* fix: 组件imagepreview点击视频遮罩关闭(#1729)

* fix: 解决 Picker 在微信小程序中无法使用问题 (#1774)

* fix: 修改 Picker 组件 v-model 失效问题

* fix: 组件NoticeBar修改height之后,垂直轮播会卡顿

* fix: 删除Datepicker Demo演示多余内容

* fix: 组件Picker在JD小程序上适配

* fix: 组件Address京东小程序适配

* feat: 京东小程序适配

* fix: 删除空格

* feat: 删除console

* fix: 京东小程序imagepreview适配

* fix: 修复 imagepreview 动态设置 initNo 显示不正确问题

* fix: 组件 InfiniteLoading 某些情况下会错误触发下拉刷新#1819

* fix: 删除pullrefresh

* feat: 组件 imagepreview瘦身

* feat: 组件Picker 瘦身

* fix: address线上问题修改

* fix: 完善imagepreview

* feat: 公共函数提取

* feat: 函数式改用 createComponent

* fix: 文件回撤

* feat: 单元测试修改

* fix: 组件uploader上传

* feat: upload优化

* fix: 组件uploaderuploader 类优化

* fix: createComponent 修改
yangxiaolu1993 3 years ago
parent
commit
2c009ebd3c

+ 23 - 29
src/packages/__VUE/uploader/index.taro.vue

@@ -9,13 +9,15 @@
 
 
     <view class="nut-uploader__preview" :class="[listType]" v-for="(item, index) in fileList" :key="item.uid">
     <view class="nut-uploader__preview" :class="[listType]" v-for="(item, index) in fileList" :key="item.uid">
       <view class="nut-uploader__preview-img" v-if="listType == 'picture' && !$slots.default">
       <view class="nut-uploader__preview-img" v-if="listType == 'picture' && !$slots.default">
-        <view class="nut-uploader__preview__progress" v-if="item.status == 'ready'">
-          <view class="nut-uploader__preview__progress__msg">{{ item.message }}</view>
-        </view>
-        <view class="nut-uploader__preview__progress" v-else-if="item.status != 'success'">
-          <nut-icon color="#fff" :name="item.status == 'error' ? 'failure' : 'loading'"></nut-icon>
+        <view class="nut-uploader__preview__progress" v-if="item.status != 'success'">
+          <nut-icon
+            color="#fff"
+            :name="item.status == 'error' ? 'failure' : 'loading'"
+            v-if="item.status != 'ready'"
+          ></nut-icon>
           <view class="nut-uploader__preview__progress__msg">{{ item.message }}</view>
           <view class="nut-uploader__preview__progress__msg">{{ item.message }}</view>
         </view>
         </view>
+
         <nut-icon
         <nut-icon
           v-if="isDeletable"
           v-if="isDeletable"
           v-bind="$attrs"
           v-bind="$attrs"
@@ -70,8 +72,9 @@
 <script lang="ts">
 <script lang="ts">
 import { computed, onMounted, PropType, reactive } from 'vue';
 import { computed, onMounted, PropType, reactive } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 import { createComponent } from '@/packages/utils/create';
-import { Uploader, UploadOptions } from './uploader';
+import { UploaderTaro, UploadOptions } from './uploader';
 import { FileItem } from './type';
 import { FileItem } from './type';
+import { funInterceptor, Interceptor } from '@/packages/utils/util';
 const { componentName, create, translate } = createComponent('uploader');
 const { componentName, create, translate } = createComponent('uploader');
 import Taro from '@tarojs/taro';
 import Taro from '@tarojs/taro';
 import { isPromise } from '@/packages/utils/util';
 import { isPromise } from '@/packages/utils/util';
@@ -118,7 +121,7 @@ export default create({
       default: null
       default: null
     },
     },
     beforeDelete: {
     beforeDelete: {
-      type: Function,
+      type: Function as PropType<Interceptor>,
       default: (file: import('./type').FileItem, files: import('./type').FileItem[]) => {
       default: (file: import('./type').FileItem, files: import('./type').FileItem[]) => {
         return true;
         return true;
       }
       }
@@ -138,7 +141,7 @@ export default create({
   ],
   ],
   setup(props, { emit }) {
   setup(props, { emit }) {
     const fileList = reactive(props.fileList) as Array<import('./type').FileItem>;
     const fileList = reactive(props.fileList) as Array<import('./type').FileItem>;
-    let uploadQueue: Promise<Uploader>[] = [];
+    let uploadQueue: Promise<UploaderTaro>[] = [];
 
 
     const classes = computed(() => {
     const classes = computed(() => {
       const prefixCls = componentName;
       const prefixCls = componentName;
@@ -227,7 +230,7 @@ export default create({
           fileItem
           fileItem
         });
         });
       };
       };
-      let task = new Uploader(uploadOption);
+      let task = new UploaderTaro(uploadOption);
       if (props.autoUpload) {
       if (props.autoUpload) {
         task.uploadTaro(Taro.uploadFile, Taro.getEnv());
         task.uploadTaro(Taro.uploadFile, Taro.getEnv());
       } else {
       } else {
@@ -319,20 +322,10 @@ export default create({
 
 
     const onDelete = (file: import('./type').FileItem, index: number) => {
     const onDelete = (file: import('./type').FileItem, index: number) => {
       clearUploadQueue(index);
       clearUploadQueue(index);
-      let fn = props.beforeDelete(file, fileList);
-      if (isPromise(fn)) {
-        fn.then((res) => {
-          if (res) {
-            deleted(file, index);
-          }
-        }).catch((error) => {
-          console.log(error, '用户阻止了删除!');
-        });
-      } else if (fn) {
-        deleted(file, index);
-      } else {
-        console.log('用户阻止了删除!');
-      }
+      funInterceptor(props.beforeDelete, {
+        args: [file, fileList],
+        done: () => deleted(file, index)
+      });
     };
     };
 
 
     const onChange = (res: Taro.chooseImage.SuccessCallbackResult) => {
     const onChange = (res: Taro.chooseImage.SuccessCallbackResult) => {
@@ -340,13 +333,9 @@ export default create({
       const { tempFilePaths, tempFiles } = res;
       const { tempFilePaths, tempFiles } = res;
 
 
       if (props.beforeUpload) {
       if (props.beforeUpload) {
-        props.beforeUpload(tempFiles).then((f: Array<Taro.chooseImage.ImageFile>) => {
-          const _files: Taro.chooseImage.ImageFile[] = filterFiles(f);
-          readFile(_files);
-        });
+        props.beforeUpload(tempFiles).then((f: Array<Taro.chooseImage.ImageFile>) => changeReadFile(f));
       } else {
       } else {
-        const _files: Taro.chooseImage.ImageFile[] = filterFiles(tempFiles);
-        readFile(_files);
+        changeReadFile(tempFiles);
       }
       }
 
 
       emit('change', {
       emit('change', {
@@ -354,6 +343,11 @@ export default create({
       });
       });
     };
     };
 
 
+    const changeReadFile = (f: any) => {
+      const _files: Taro.chooseImage.ImageFile[] = filterFiles(f);
+      readFile(_files);
+    };
+
     return {
     return {
       onDelete,
       onDelete,
       fileList,
       fileList,

+ 45 - 74
src/packages/__VUE/uploader/index.vue

@@ -2,40 +2,20 @@
   <view :class="classes">
   <view :class="classes">
     <view class="nut-uploader__slot" v-if="$slots.default">
     <view class="nut-uploader__slot" v-if="$slots.default">
       <slot></slot>
       <slot></slot>
-      <template v-if="maximum - fileList.length">
-        <input
-          class="nut-uploader__input"
-          v-if="capture"
-          type="file"
-          capture="camera"
-          :accept="accept"
-          :multiple="multiple"
-          :name="name"
-          :disabled="disabled"
-          @change="onChange"
-        />
-        <input
-          class="nut-uploader__input"
-          v-else
-          type="file"
-          :accept="accept"
-          :multiple="multiple"
-          :name="name"
-          :disabled="disabled"
-          @change="onChange"
-        />
-      </template>
+      <component :is="renderInput" @change="onChange" v-if="maximum - fileList.length"></component>
     </view>
     </view>
 
 
     <view class="nut-uploader__preview" :class="[listType]" v-for="(item, index) in fileList" :key="item.uid">
     <view class="nut-uploader__preview" :class="[listType]" v-for="(item, index) in fileList" :key="item.uid">
       <view class="nut-uploader__preview-img" v-if="listType == 'picture' && !$slots.default">
       <view class="nut-uploader__preview-img" v-if="listType == 'picture' && !$slots.default">
-        <view class="nut-uploader__preview__progress" v-if="item.status == 'ready'">
-          <view class="nut-uploader__preview__progress__msg">{{ item.message }}</view>
-        </view>
-        <view class="nut-uploader__preview__progress" v-else-if="item.status != 'success'">
-          <nut-icon color="#fff" :name="item.status == 'error' ? 'failure' : 'loading'"></nut-icon>
+        <view class="nut-uploader__preview__progress" v-if="item.status != 'success'">
+          <nut-icon
+            color="#fff"
+            :name="item.status == 'error' ? 'failure' : 'loading'"
+            v-if="item.status != 'ready'"
+          ></nut-icon>
           <view class="nut-uploader__preview__progress__msg">{{ item.message }}</view>
           <view class="nut-uploader__preview__progress__msg">{{ item.message }}</view>
         </view>
         </view>
+
         <nut-icon
         <nut-icon
           v-if="isDeletable"
           v-if="isDeletable"
           v-bind="$attrs"
           v-bind="$attrs"
@@ -54,8 +34,10 @@
             <nut-icon color="#808080" name="link"></nut-icon>&nbsp;{{ item.name }}
             <nut-icon color="#808080" name="link"></nut-icon>&nbsp;{{ item.name }}
           </view>
           </view>
         </view>
         </view>
+
         <view class="tips">{{ item.name }}</view>
         <view class="tips">{{ item.name }}</view>
       </view>
       </view>
+
       <view class="nut-uploader__preview-list" v-else-if="listType == 'list'">
       <view class="nut-uploader__preview-list" v-else-if="listType == 'list'">
         <view @click="fileItemClick(item)" class="nut-uploader__preview-img__file__name" :class="[item.status]">
         <view @click="fileItemClick(item)" class="nut-uploader__preview-img__file__name" :class="[item.status]">
           <nut-icon name="link" />&nbsp;{{ item.name }}
           <nut-icon name="link" />&nbsp;{{ item.name }}
@@ -76,43 +58,25 @@
         </nut-progress>
         </nut-progress>
       </view>
       </view>
     </view>
     </view>
+
     <view
     <view
       class="nut-uploader__upload"
       class="nut-uploader__upload"
       :class="[listType]"
       :class="[listType]"
       v-if="listType == 'picture' && !$slots.default && maximum - fileList.length"
       v-if="listType == 'picture' && !$slots.default && maximum - fileList.length"
     >
     >
       <nut-icon v-bind="$attrs" :size="uploadIconSize" color="#808080" :name="uploadIcon"></nut-icon>
       <nut-icon v-bind="$attrs" :size="uploadIconSize" color="#808080" :name="uploadIcon"></nut-icon>
-      <input
-        class="nut-uploader__input"
-        v-if="capture"
-        type="file"
-        capture="camera"
-        :accept="accept"
-        :multiple="multiple"
-        :name="name"
-        :disabled="disabled"
-        @change="onChange"
-      />
-      <input
-        class="nut-uploader__input"
-        v-else
-        type="file"
-        :accept="accept"
-        :multiple="multiple"
-        :name="name"
-        :disabled="disabled"
-        @change="onChange"
-      />
+
+      <component :is="renderInput" @change="onChange"></component>
     </view>
     </view>
   </view>
   </view>
 </template>
 </template>
 
 
 <script lang="ts">
 <script lang="ts">
-import { computed, reactive } from 'vue';
+import { computed, reactive, h, PropType } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 import { createComponent } from '@/packages/utils/create';
 import { Uploader, UploadOptions } from './uploader';
 import { Uploader, UploadOptions } from './uploader';
 import { FileItem } from './type';
 import { FileItem } from './type';
-import { isPromise } from '@/packages/utils/util';
+import { funInterceptor, Interceptor } from '@/packages/utils/util';
 const { componentName, create, translate } = createComponent('uploader');
 const { componentName, create, translate } = createComponent('uploader');
 export default create({
 export default create({
   props: {
   props: {
@@ -150,13 +114,12 @@ export default create({
       default: null
       default: null
     },
     },
     beforeDelete: {
     beforeDelete: {
-      type: Function,
+      type: Function as PropType<Interceptor>,
       default: (file: import('./type').FileItem, files: import('./type').FileItem[]) => {
       default: (file: import('./type').FileItem, files: import('./type').FileItem[]) => {
         return true;
         return true;
       }
       }
     },
     },
     onChange: { type: Function }
     onChange: { type: Function }
-    // customRequest: { type: Function }
   },
   },
   emits: [
   emits: [
     'start',
     'start',
@@ -180,6 +143,21 @@ export default create({
       };
       };
     });
     });
 
 
+    const renderInput = () => {
+      let params: any = {
+        class: `nut-uploader__input`,
+        type: 'file',
+        accept: props.accept,
+        multiple: props.multiple,
+        name: props.name,
+        disabled: props.disabled
+      };
+
+      if (props.capture) params.capture = 'camera';
+
+      return h('input', params);
+    };
+
     const clearInput = (el: HTMLInputElement) => {
     const clearInput = (el: HTMLInputElement) => {
       el.value = '';
       el.value = '';
     };
     };
@@ -244,6 +222,7 @@ export default create({
         );
         );
       }
       }
     };
     };
+
     const clearUploadQueue = (index = -1) => {
     const clearUploadQueue = (index = -1) => {
       if (index > -1) {
       if (index > -1) {
         uploadQueue.splice(index, 1);
         uploadQueue.splice(index, 1);
@@ -320,20 +299,10 @@ export default create({
 
 
     const onDelete = (file: import('./type').FileItem, index: number) => {
     const onDelete = (file: import('./type').FileItem, index: number) => {
       clearUploadQueue(index);
       clearUploadQueue(index);
-      let fn = props.beforeDelete(file, fileList);
-      if (isPromise(fn)) {
-        fn.then((res) => {
-          if (res) {
-            deleted(file, index);
-          }
-        }).catch((error) => {
-          console.log(error, '用户阻止了删除!');
-        });
-      } else if (fn) {
-        deleted(file, index);
-      } else {
-        console.log('用户阻止了删除!');
-      }
+      funInterceptor(props.beforeDelete, {
+        args: [file, fileList],
+        done: () => deleted(file, index)
+      });
     };
     };
 
 
     const onChange = (event: InputEvent) => {
     const onChange = (event: InputEvent) => {
@@ -344,13 +313,9 @@ export default create({
       let { files } = $el;
       let { files } = $el;
 
 
       if (props.beforeUpload) {
       if (props.beforeUpload) {
-        props.beforeUpload(files).then((f: Array<File>) => {
-          const _files: File[] = filterFiles(new Array<File>().slice.call(f));
-          readFile(_files);
-        });
+        props.beforeUpload(files).then((f: Array<File>) => changeReadFile(f));
       } else {
       } else {
-        const _files: File[] = filterFiles(new Array<File>().slice.call(files));
-        readFile(_files);
+        changeReadFile(files);
       }
       }
 
 
       emit('change', {
       emit('change', {
@@ -363,6 +328,11 @@ export default create({
       }
       }
     };
     };
 
 
+    const changeReadFile = (f: any) => {
+      const _files: File[] = filterFiles(new Array<File>().slice.call(f));
+      readFile(_files);
+    };
+
     return {
     return {
       onChange,
       onChange,
       onDelete,
       onDelete,
@@ -370,7 +340,8 @@ export default create({
       classes,
       classes,
       fileItemClick,
       fileItemClick,
       clearUploadQueue,
       clearUploadQueue,
-      submit
+      submit,
+      renderInput
     };
     };
   }
   }
 });
 });

+ 6 - 4
src/packages/__VUE/uploader/uploader.ts

@@ -58,6 +58,12 @@ export class Uploader {
       console.warn('浏览器不支持 XMLHttpRequest');
       console.warn('浏览器不支持 XMLHttpRequest');
     }
     }
   }
   }
+}
+
+export class UploaderTaro extends Uploader {
+  constructor(options: UploadOptions) {
+    super(options);
+  }
   uploadTaro(uploadFile: Function, env: string) {
   uploadTaro(uploadFile: Function, env: string) {
     const options = this.options;
     const options = this.options;
     if (env === 'WEB') {
     if (env === 'WEB') {
@@ -90,11 +96,7 @@ export class Uploader {
         options.onStart?.(options);
         options.onStart?.(options);
         uploadTask.progress((res: { progress: any; totalBytesSent: any; totalBytesExpectedToSend: any }) => {
         uploadTask.progress((res: { progress: any; totalBytesSent: any; totalBytesExpectedToSend: any }) => {
           options.onProgress?.(res, options);
           options.onProgress?.(res, options);
-          // console.log('上传进度', res.progress);
-          // console.log('已经上传的数据长度', res.totalBytesSent);
-          // console.log('预期需要上传的数据总长度', res.totalBytesExpectedToSend);
         });
         });
-        // uploadTask.abort(); // 取消上传任务
       }
       }
     }
     }
   }
   }

+ 2 - 2
src/packages/utils/Interceptor.ts

@@ -9,7 +9,7 @@ export const funInterceptor = (
     canceled
     canceled
   }: {
   }: {
     args?: unknown[];
     args?: unknown[];
-    done: () => void;
+    done: (val?: any) => void;
     canceled?: () => void;
     canceled?: () => void;
   }
   }
 ) => {
 ) => {
@@ -20,7 +20,7 @@ export const funInterceptor = (
       returnVal
       returnVal
         .then((value) => {
         .then((value) => {
           if (value) {
           if (value) {
-            done();
+            done(value);
           } else if (canceled) {
           } else if (canceled) {
             canceled();
             canceled();
           }
           }

+ 1 - 1
src/packages/utils/create/mountComponent.ts

@@ -12,7 +12,7 @@ export const CreateComponent = (options: any, component: any) => {
     }
     }
   }
   }
   const root = document.createElement('view');
   const root = document.createElement('view');
-  const name = component.name && component.name + '-';
+  const name = component.name ? component.name + '-' : '';
   const id1 = options.id || new Date().getTime();
   const id1 = options.id || new Date().getTime();
   root.id = name + id1;
   root.id = name + id1;