Skip to content

Uploader 图片上传

介绍

用于将本地的图片上传至服务器,并在上传过程中展示预览图和上传进度。

基础用法

通过 v-model 属性设置图片数据。

html
<vd-uploader v-model="files" />
ts
const files = ref([
  'http://vital-design.cn/ui/static/exh-1.jpg',
  'http://vital-design.cn/ui/static/exh-2.jpg',
]);

多选上传

通过 multiple 属性开启/关闭多选模式。

html
<vd-uploader v-model="files" :multiple="true" />
ts
const files = ref([
  'http://vital-design.cn/ui/static/exh-1.jpg',
  'http://vital-design.cn/ui/static/exh-2.jpg',
]);

限制上传数量

通过 limit 属性限制上传数量。

html
<vd-uploader v-model="files" :limit="3" />
ts
const files = ref([
  'http://vital-design.cn/ui/static/exh-1.jpg',
  'http://vital-design.cn/ui/static/exh-2.jpg',
]);

搭配裁切组件

通过 after-choose 在选图之后、写入列表之前异步处理图片(如裁切、压缩)。入参为 (paths, files),可返回新的 paths;返回 false 取消本次选择。

下面示例用 showPopup + ImageCropper 逐张裁切。ImageCropper 基于 canvas 导出静态图,GIF 动图裁切后会丢失动画,因此示例用 getFileSuffix 跳过 .gif,直接保留原路径;其它格式进入裁切,取消则跳过该张:

html
<vd-uploader v-model="files" :after-choose="afterChoose" />

<vd-popup
  name="cropper"
  position="bottom"
  round
  title="裁切图片"
  title-align="center"
  :close-on-click-overlay="false"
>
  <vd-image-cropper
    ref="cropperRef"
    :src="cropper.src"
    height="60vh"
  />

  <vd-button @click="closePopup('cropper')">取消</vd-button>
  <vd-button type="primary" @click="onCropConfirm">完成</vd-button>
</vd-popup>
ts
import type { UploaderAfterChoose, ImageCropperInstance } from 'vital-design';
import { showPopup, closePopup } from 'vital-design';
import { getFileSuffix } from '@vital-design/shared';

const cropperRef = ref<ImageCropperInstance>();

const cropper = reactive({
  src: '',
  path: '',
});

async function onCropConfirm() {
  const path = await cropperRef.value?.crop();

  cropper.path = path || '';
  closePopup('cropper');
}

const afterChoose: UploaderAfterChoose = async (paths) => {
  const next: string[] = [];

  for (const src of paths) {
    const suffix = getFileSuffix(src);

    // GIF 跳过裁切,避免动画丢失
    if (suffix !== 'gif') {
      cropper.src = src;
      cropper.path = '';
      await showPopup({ name: 'cropper' });
    } else {
      cropper.path = src;
    }

    if (!cropper.path) {
      continue;
    }

    next.push(cropper.path);
  }

  return next;
};

上传状态

文件上传完毕后会触发 after-read 回调函数,可获取到对应的 file 对象,通过 status 属性设置上传状态,支持 uploadingdeletingfaileddone 状态。

html
<vd-uploader
  v-model="files"
  :multiple="true"
  :after-read="afterRead"
/>
ts
import { UploaderFileItem } from 'vital-design';
import { timeout, randomId, toArray } from '@vital-design/shared';

const images = [
  'http://vital-design.cn/ui/static/exh-1.jpg',
  'http://vital-design.cn/ui/static/exh-2.jpg',
  'http://vital-design.cn/ui/static/exh-3.jpg',
];

const files = ref<UploaderFileItem[]>([
  { url: images[0], status: 'uploading', message: '上传中...' },
  { url: images[1], status: 'failed', message: '上传失败' },
  { url: images[2] }
]);

const afterRead: UploaderAfterRead = async (files) => {
  files = toArray(files);

  for (const file of files) {
    if (!file.id) {
      file.id = randomId();
    }

    file.status = 'uploading';
    file.percentage = 0;

    // 模拟请求上传
    let rate = 0;
    while (rate < 100) {
      await timeout(300);
      const add = Math.random() * 8;
      rate = Math.min(rate + add, 100);
      file.percentage = rate.toFixed(2);
    }

    file.status = 'done';
    file.percentage = '';
  }
}

允许排序

通过 sortable 属性开启/关闭排序功能。

html
<vd-uploader v-model="files" :sortable="true" />
ts
const files = ref([
  'http://vital-design.cn/ui/static/exh-1.jpg',
  'http://vital-design.cn/ui/static/exh-2.jpg',
]);

一行展示列数

通过 columns 属性设置一行展示的列数。

html
<vd-uploader v-model="files" :columns="4" />
ts
const files = ref([
  'http://vital-design.cn/ui/static/exh-1.jpg',
  'http://vital-design.cn/ui/static/exh-2.jpg',
]);

删除状态

通过 before-delete 属性设置删除状态,支持 Promise

html
<vd-uploader v-model="files" :before-delete="beforeDelete" />
<vd-dialog name="page" />
ts
const files = ref([
  'http://vital-design.cn/ui/static/exh-1.jpg',
  'http://vital-design.cn/ui/static/exh-2.jpg',
]);

const beforeDelete: UploaderBeforeDelete = async (file, index) => {
  try {
    await showDialog({
      title: '提示',
      message: '是否确认删除?',
      showCancelButton: true,
      name: 'page',
    });

    console.log('确认删除');
    await timeout(1000);
  } catch (error) {
    console.log('取消删除');
    return false;
  }
}

只读状态

通过 readonly 属性设置只读状态。

html
<vd-uploader v-model="files" readonly />
ts
const files = ref([
  'http://vital-design.cn/ui/static/exh-1.jpg',
  'http://vital-design.cn/ui/static/exh-2.jpg',
]);

API

Props

参数说明类型默认值
v-model选中值(string | UploaderFileItem)[]-
multiple是否允许多选boolean-
limit最大上传数量string | number-
size-type上传图片尺寸类型UploaderSizeType[]['original', 'compressed']
source-type上传图片源类型UploaderSourceType[]['camera', 'album']
crop图像裁剪参数,设置后 size-type 失效UploaderCrop-
preview是否展示图片预览booleantrue
preview-name指定图片预览组件标识名称string-
reupload是否开启覆盖上传boolean-
deletable是否展示删除按钮booleantrue
disabled是否禁用boolean-
readonly是否只读boolean-
icon上传区域的图标IconsNamepic
text上传区域的文字string-
image-mode图片裁剪、缩放的模式ImageModescaleToFill
before-read读取文件前的回调函数,支持 PromiseUploaderBeforeRead-
after-choose选择图片后的回调函数,支持 Promise;返回新 pathsfalseUploaderAfterChoose-
after-read读取文件后的回调函数UploaderAfterRead-
before-delete删除文件前的回调函数,支持 PromiseUploaderBeforeDelete-

代替原始 Props

参数说明类型默认值
custom-id根节点idstring-
custom-class根节点类名ClassValue-
custom-style根节点样式StyleValue-

Events

事件名说明回调参数
click点击时触发MouseEvent
update:model-value文件列表更新时触发UploaderFileItem[]
click-view点击视图时触发UploaderOnClickViewEvent
sort-start排序开始时触发UploaderOnSortStartEvent
sort-change排序改变时触发UploaderOnSortChangeEvent
sort-end排序结束时触发UploaderOnSortEndEvent

Slots

名称说明
image图片
trigger触发按钮

Expose

方法名说明参数返回值
upload触发上传index?: numberPromise<void>
reupload触发重新上传index: number-
delete删除文件index: numberPromise<void>

类型定义

组件导出以下类型定义:

ts
import type {
  UploaderFileItem,
  UploaderChooseFile,
  UploaderBeforeRead,
  UploaderAfterChoose,
  UploaderAfterRead,
  UploaderBeforeDelete,
  UploaderOnClickViewEvent,
  UploaderOnSortStartEvent,
  UploaderOnSortChangeEvent,
  UploaderOnSortEndEvent,
  UploaderExpose,
  UploaderInstance,
} from 'vital-design';

赣ICP备2025061025号-1