본문으로 바로가기 본문 바로가기
WIKI 기술 지식 베이스

Upload 업로드

원문 보기 위키 갱신

파일을 업로드할 때 사용하는 컴포넌트예요.

출처: 문서

본문

언제 사용하나요

파일을 백엔드 서버로 올려야 할 때 사용해요.

기본 사용법

:::demo

<template>
  <d-upload v-model="uploadedFiles" :upload-options="uploadOptions" />
</template>
<script>
import { ref } from 'vue';

export default {
  setup() {
    const uploadedFiles = ref([]);
    const uploadOptions = ref({
      uri: 'https://run.mocky.io/v3/132b3ea3-23ea-436b-aed4-c43ef9d116f0',
    });

    return {
      uploadedFiles,
      uploadOptions,
    };
  },
};
</script>

:::

여러 파일 업로드

multiple 속성을 쓰면 여러 파일 업로드를 지원하고, limit 속성으로 파일 수 상한을 정할 수 있어요. 업로드 수가 제한을 넘으면 on-exceed 훅 함수가 호출돼요.

:::demo

<template>
  <d-upload
    v-model="uploadedFiles"
    :upload-options="uploadOptions"
    multiple
    :limit="2"
    :on-exceed="handleExceed"
    :on-change="handleChange"
    :on-preview="onPreview"
  />
</template>
<script>
import { ref } from 'vue';

export default {
  setup() {
    const uploadedFiles = ref([]);
    const uploadOptions = ref({
      uri: 'https://run.mocky.io/v3/132b3ea3-23ea-436b-aed4-c43ef9d116f0',
    });
    const handleExceed = (files, uploadFiles) => {
      console.log('onExceed:', files);
      console.log('onExceed:', uploadFiles);
      throw new Error('文件数上限为 2');
    };
    const handleChange = (files, uploadFiles) => {
      console.log('onChange:', files);
      console.log('onChange:', uploadFiles);
    };

    const onPreview = (file) => {
      console.log('previewFile: ', file);
    };
    return {
      uploadedFiles,
      uploadOptions,
      handleExceed,
      handleChange,
      onPreview,
    };
  },
};
</script>

:::

파일 드래그 업로드

:::demo

<template>
  <d-upload v-model="uploadedFiles" :upload-options="uploadOptions" droppable />
</template>
<script>
import { ref } from 'vue';

export default {
  setup() {
    const uploadedFiles = ref([]);
    const uploadOptions = ref({
      uri: 'https://run.mocky.io/v3/132b3ea3-23ea-436b-aed4-c43ef9d116f0',
    });

    return {
      uploadedFiles,
      uploadOptions,
    };
  },
};
</script>

:::

수동 업로드와 비우기

auto-upload를 false로 설정하면 파일을 고른 직후 바로 업로드되는 동작을 막을 수 있어요. 이후 submit 메서드로 수동 업로드를 진행해요. clearFiles 메서드를 사용하면 업로드된 파일과 선택된 파일을 모두 깔끔하게 비울 수 있어요.

:::demo

<template>
  <div>
    <d-upload ref="demoUpload" multiple v-model="uploadedFiles" :upload-options="uploadOptions" :auto-upload="false" />
    <d-button @click="submit" style="margin-top: 20px">手动上传</d-button>
    <d-button @click="clear" style="margin: 20px 0px 0px 10px;">清空文件</d-button>
  </div>
</template>
<script>
import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    const uploadedFiles = ref([]);
    const uploadOptions = ref({
      uri: 'https://run.mocky.io/v3/132b3ea3-23ea-436b-aed4-c43ef9d116f0',
    });
    const demoUpload = ref(null);
    const submit = () => {
      demoUpload.value.submit();
    };
    const clear = () => {
      demoUpload.value.clearFiles();
    };

    return {
      uploadedFiles,
      uploadOptions,
      demoUpload,
      submit,
      clear,
    };
  },
});
</script>

:::

업로드 막기

:::demo

<template>
  <d-upload v-model="uploadedFiles" :upload-options="uploadOptions" disabled />
</template>
<script>
import { ref } from 'vue';

export default {
  setup() {
    const uploadedFiles = ref([]);
    const uploadOptions = ref({
      uri: 'https://run.mocky.io/v3/132b3ea3-23ea-436b-aed4-c43ef9d116f0',
    });

    return {
      uploadedFiles,
      uploadOptions,
    };
  },
};
</script>

:::

원하는 영역에서 업로드하기

:::demo 기본 slot을 사용하면 파일을 원하는 영역에서 업로드할 수 있어요.

<template>
  <d-upload
    class="upload-demo"
    accept=".png"
    v-model="uploadedFiles"
    :upload-options="uploadOptions"
    droppable
    :on-success="onSuccess"
    :on-error="onError"
    :on-progress="onProgress"
    :before-upload="beforeUpload"
    @file-over="fileOver"
    @file-drop="fileDrop"
    @file-select="fileSelect"
    @delete-uploaded-file="deleteUploadedFile"
  >
    <div class="upload-trigger">
      <div><d-icon name="upload" size="24px"></d-icon></div>
      <div style="margin-top: 20px;">
        将文件拖到此处,或
        <span class="link">点击上传</span>
      </div>
    </div>
    <template v-slot:uploaded-files="slotProps">
      <table class="table uploaded-files" v-if="slotProps.uploadedFiles.length > 0">
        <tbody>
          <tr v-for="(uploadedFile, index) in slotProps.uploadedFiles" :key="index" class="row">
            <td width="50%">
              <span>{{ uploadedFile.name }}</span>
            </td>
            <td width="25%">
              <span>Uploaded</span>
            </td>
            <td>
              <d-button size="xs" @click="(event) => slotProps.deleteFile(uploadedFile)">Delete</d-button>
            </td>
          </tr>
        </tbody>
      </table>
    </template>
  </d-upload>
</template>
<script>
import { ref, watch } from 'vue';

export default {
  setup() {
    const uploadedFiles = ref([
      {
        name: 'food.jpeg',
        url: 'https://devui.design/home',
      },
      {
        name: 'food2.jpeg',
        url: 'https://devui.design/home',
      },
    ]);

    const uploadOptions = ref({
      uri: 'https://run.mocky.io/v3/132b3ea3-23ea-436b-aed4-c43ef9d116f0',
    });

    const beforeUpload = (file) => {
      console.log(file);
      return true;
    };

    const onSuccess = (result) => {
      console.log('success', result);
    };

    const onError = () => {
      console.log(error);
    };

    const onProgress = (selectFile, uploadedFiles) => {
      console.log('selectFile: ', selectFile);
      console.log('uploadedFiles: ', uploadedFiles);
    };

    const fileOver = (fileInfo) => {
      console.log('fileInfo:', fileInfo);
    };

    const fileDrop = (fileInfo) => {
      console.log('fileInfo:', fileInfo);
    };

    const fileSelect = (fileInfo) => {
      console.log('fileInfo:', fileInfo);
    };

    const deleteUploadedFile = (fileInfo) => {
      console.log('fileInfo:', fileInfo);
    };

    watch(uploadedFiles, (newValue, oldValue) => {
      console.log('uploadedFiles', {
        newValue,
        oldValue,
      });
    });

    return {
      uploadedFiles,
      uploadOptions,
      beforeUpload,
      onSuccess,
      onError,
      onProgress,
      fileOver,
      fileDrop,
      fileSelect,
      deleteUploadedFile,
    };
  },
};
</script>

<style>
.upload-demo .upload-trigger {
  background-color: #fff;
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  box-sizing: border-box;
  width: 360px;
  height: 180px;
  text-align: center;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.upload-demo .upload-trigger .link {
  color: #5e7ce0;
}
</style>

:::

이미지 업로드 예제

:::demo

<template>
  <div class="img-container" v-if="!showUpload">
    <img class="img-preview" />
    <div class="delete-img" @click="handleDel">
      <d-icon name="delete" size="14px"></d-icon>
    </div>
  </div>
  <d-upload class="upload-demo-new" accept=".png" :upload-options="uploadOptions" :before-upload="beforeUpload" v-if="showUpload">
    <div class="upload-trigger">
      <d-icon name="add" size="24px"></d-icon>
    </div>
  </d-upload>
</template>
<script>
import { ref, watch, nextTick } from 'vue';

export default {
  setup() {
    const showUpload = ref(true);
    const uploadOptions = ref({
      uri: 'https://run.mocky.io/v3/132b3ea3-23ea-436b-aed4-c43ef9d116f0',
    });

    const beforeUpload = (file) => {
      const reader = new FileReader();
      reader.onload = async () => {
        showUpload.value = false;
        await nextTick();
        document.getElementsByClassName('img-preview')[0].src = reader.result;
      };
      reader.readAsDataURL(file[0].file);
      return false;
    };

    const handleDel = () => {
      showUpload.value = true;
    };

    return {
      uploadOptions,
      beforeUpload,
      showUpload,
      handleDel,
    };
  },
};
</script>

<style>
.upload-demo-new .upload-trigger {
  background-color: #fff;
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  box-sizing: border-box;
  width: 180px;
  height: 180px;
  text-align: center;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.upload-demo .upload-trigger .link {
  color: #5e7ce0;
}
.img-container {
  position: relative;
}
.img-preview {
  width: 180px;
  height: 180px;
  border-radius: 6px;
}
.delete-img {
  width: 24px;
  height: 24px;
  background-color: #f7f7f9;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  top: -12px;
  left: 168px;
}
</style>

:::

Upload 파라미터

파라미터 타입 기본값 설명 Demo 링크
accept string - 선택, 파일 업로드로 제출 가능한 파일 타입 지정,
예: accept: '.xls,.xlsx,.png'
임의 영역 업로드
before-upload boolean Promise<boolean> - 선택, 업로드 전 콜백. true or false 반환으로
파일 업로드 여부 제어. 파라미터는 파일 정보 및 업로드 설정
임의 영역 업로드
disabled boolean false 선택, 업로드 컴포넌트 비활성화 여부 업로드 금지
droppable boolean false 선택, 드래그 지원 여부 파일 드래그 업로드
multiple boolean false 선택, 다중 파일 선택 지원 여부 다중 파일 업로드
upload-options IUploadOptions - 선택, 업로드 설정 기본 사용법
uploaded-files Array<Object> - 선택, 업로드된 파일 리스트 획득 기본 사용법
on-success function([{file, response}]) - 선택, 파일 업로드 성공 시 훅 임의 영역 업로드
on-error function({file, response}) - 선택, 파일 업로드 실패 시 훅 임의 영역 업로드
on-exceed function(files, uploadFiles) - 선택, 파일 업로드 수가 제한 초과 시 훅 다중 파일 업로드
on-change function(files, uploadFiles) - 선택, 파일 상태 변경 시 훅. 파일 추가, 업로드 성공, 업로드 실패 시 모두 호출 다중 파일 업로드
on-progress function(files, uploadFiles) - 선택, 파일 업로드 시 훅 임의 영역 업로드
on-preview function(file) - 선택, 파일 리스트의 파일 클릭 시 훅 다중 파일 업로드
limit number - 선택, 업로드 가능 파일 최대 개수 다중 파일 업로드
auto-upload boolean true 선택, 파일 선택 후 즉시 업로드 여부 수동 업로드와 비우기
http-request function(files) - 선택, 기본 업로드 동작 대체. files는 선택한 파일 객체 리스트 -

Upload 이벤트

이벤트명 타입 설명 Demo 링크
delete-uploaded-file (v: string) => void 업로드 파일 삭제 콜백 함수. 삭제된 파일 경로 정보 반환 임의 영역 업로드
file-drop (v: any) => void 드래그 업로드 지원 시 현재 드래그 파일 리스트 콜백.
단일 파일 업로드는 기본적으로 첫 번째 파일 반환
임의 영역 업로드
file-over (v: boolean) => void 드래그 업로드 지원 시 파일이 드롭 가능 영역으로 이동할 때 트리거 이벤트.
드래그 가능 요소가 배치 대상에서 벗어나면 false 반환,
요소가 배치 대상으로 드래그 중이면 true 반환
임의 영역 업로드
file-select (v: File) => void 파일 선택 후 콜백 함수. 선택된 파일 정보 반환 임의 영역 업로드

Upload 메서드

메서드명 설명 Demo 링크
submit 수동으로 선택한 파일 업로드용 수동 업로드와 비우기
clearFiles 업로드된 파일과 선택된 파일 리스트 비우기용(before-upload 내 호출 미지원) 수동 업로드와 비우기

Upload 슬롯

슬롯명 기본값 설명 Demo 링크
default -- 기본 콘텐츠 커스텀 임의 영역 업로드
uploaded-files -- 선택, 커스텀 업로드 완료 파일 리스트 템플릿 생성용. 파라미터는 {uploadedFiles, deleteFile} 임의 영역 업로드

Upload 타입 정의

IUploadOptions

export class IUploadOptions {
  // 上传接口地址
  uri: string;
  // http 请求方法
  method?: string;
  // 上传文件大小限制
  maximumSize?: number;
  // 自定义请求headers
  headers?: { [key: string]: any };
  // 认证token
  authToken?: string;
  // 认证token header标示
  authTokenHeader?: string;
  // 上传额外自定义参数
  additionalParameter?: { [key: string]: any };
  // 上传文件字段名称,默认file
  fileFieldName?: string;
  // 多文件上传,是否检查文件重名,设置为true,重名文件不会覆盖,否则会覆盖上传
  checkSameName?: boolean;
  // 指示了是否该使用类似cookies,authorization headers(头部授权)或者TLS客户端证书这一类资格证书来创建一个跨站点访问控制(cross-site Access-Control)请求
  withCredentials?: boolean;
  //  手动设置返回数据类型
  responseType?: 'arraybuffer' | 'blob' | 'json' | 'text';
}

더 알아보기 (Learn more)

upload-options로 업로드 주소와 헤더 등을 설정하고, 훅 함수로 업로드 과정을 세밀하게 제어할 수 있어요. 자세한 내용은 DevUI 공식 문서를 확인해 보세요.