Va.FileDropUpload — 드래그앤드롭 파일 업로드 영역
드래그앤드롭이 주된 UI인 파일 업로드 컴포넌트. 사용자가 파일을 창 안에 끌어다 놓으면 자동으로 읽어 이벤트를 dispatch합니다. 파일 내용을 텍스트로 읽을지 DataURL(base64)로 읽을지 옵션으로 선택 가능.
- 클래스: Va.FileDropUpload — va_component.js:12504
- short name: fileDropUpload
- 상속: Va.Component (PureField 아님!)
- isContainer: true
- 베이스 CSS: va-file-upload-div
1. 기본 사용
{
tagName: 'fileDropUpload',
text: '파일을 여기 놓으세요',
fileType: 'binary', // 'text' / 'binary'
style: {
width: '100%',
height: '200px',
border: '2px dashed gray',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
},
onFiledrop: 'onFileDropped'
}
렌더 결과:
- 안내 텍스트가 표시된 드롭 영역
- 파일을 드래그하면 빨간 outline 표시
- 드롭 시 파일 자동 읽기 → 이벤트 dispatch
2. File / ImageFile / FileDropUpload의 차이
항목Va.FileVa.ImageFileVa.FileDropUpload
| UI 형태 | 표시 + 두 버튼 | 이미지 미리보기 + 필드 | 드롭 영역만 |
| 파일 선택 다이얼로그 | ✓ (File 버튼) | ✓ | ✕ (드래그만) |
| 드래그앤드롭 | ✕ | ✓ | ✓ (핵심) |
| 파일 내용 자동 읽기 | ✕ (수동) | ✓ (이미지만) | ✓ (fileType 옵션) |
| 미리보기 | ✕ | ✓ (이미지) | ✕ (개발자가 처리) |
| 파일 목록 UI | ✓ (파일명) | ✓ | ✕ (자유 커스텀) |
| 상속 | PureField | PureField | Component |
한 줄 요약: "드래그앤드롭 전용 파일 업로드 영역 — 커스텀 UI 자유도 높음."
3. 주요 속성
FileDropUpload 전용
속성기본값설명
| fileType | 'binary' | 파일 읽기 방식 — 'text' / 'binary' |
| text | — | 드롭 영역에 표시할 안내 텍스트 |
| innerHTML | — | HTML 안내 콘텐츠 |
| disabled / readonly | — | 상태 |
fileType 두 가지
값읽기 방식반환 형태언제
| 'text' | FileReader.readAsText() | 문자열 | CSV, JSON, TXT 등 텍스트 파일 |
| 'binary' (기본) | FileReader.readAsDataURL() | DataURL (base64) | 이미지, PDF, 바이너리 |
⚠️ 이름은 'binary'지만 실제로는 DataURL 형식 (base64 인코딩). 진짜 ArrayBuffer 원시 바이너리가 필요하면 별도 처리.
⚠️ fileType이 없거나 인식 안 되는 값이면 Va.Alert로 "fileType 설정이 없습니다" 표시 (va_component.js:12626-12630) — 명시 지정 권장.
4. 이벤트
이벤트시그니처발생 시점
| filedrop | (component, element, result, evt) | 파일 드롭 후 읽기 완료. result가 텍스트 또는 DataURL |
| change | (component, element, files, evt) | 드롭과 동시에 dispatch. files는 FileList |
⚠️ 두 이벤트가 함께 발생 — filedrop은 파일 내용, change는 파일 목록. 필요에 따라 선택.
filedrop 콜백 예시
onFileDropped(comp, el, result, evt) {
// fileType: 'binary'면 result는 DataURL
// 이미지로 표시하고 싶다면:
document.getElementById('preview').src = result;
// 또는 서버 전송용 FormData 생성
const files = comp.fieldElement.files;
const formData = new FormData();
for (let i = 0; i < files.length; i++) {
formData.append('files', files[i]);
}
UploadService.send(this, formData, ...);
}
change 콜백 예시 (파일 정보만 필요할 때)
onChange(comp, el, files, evt) {
for (let i = 0; i < files.length; i++) {
console.log(files[i].name, files[i].size);
}
}
5. 메서드
상태
메서드설명
| setDisabled(bool) / setReadonly(bool) | 상태 |
표시
메서드설명
| setText(text) | 안내 텍스트 변경 |
| setInnerHTML(html) | HTML 안내 콘텐츠 변경 |
주목: 별도의 파일 조회 메서드가 없음. component.fieldElement.files에 직접 접근하거나 change 콜백에서 받아 사용.
6. 내부 구조
<div elname="element" class="va-file-upload-div" tabindex="0">
<div elname="inner" class="file-upload-div-inner"
style="width:100%; height:100%">
<span elname="text">파일을 여기 놓으세요</span>
<input elname="field" type="file" style="display:none">
</div>
</div>
핵심 트릭:
- <input type="file">은 숨겨져 있음 — 파일 선택 다이얼로그가 아니라 드롭 이벤트만 받음
- 드롭 시 fieldElement.files에 직접 세팅 — 브라우저의 드롭 API로 받은 FileList를 input에 할당
- 드래그 시 빨간 outline — 시각적 피드백
7. 드래그앤드롭 시각 피드백
내부적으로 세 이벤트를 처리:
innerElement.ondragover = (e) => e.preventDefault(); // 드롭 허용
innerElement.ondragenter = () => outline = 'solid red 1px'; // 진입 시 빨간 테두리
innerElement.ondragleave = () => outline = ''; // 벗어나면 제거
innerElement.ondrop = async (e) => { /* 파일 처리 */ };
빨간 outline이 하드코딩되어 있음 — 테마 색상으로 바꾸려면 CSS 커스터마이즈 필요.
8. 브라우저 API 활용
파일 처리에 세 가지 API를 순서대로 시도:
- File System Access API (getAsFileSystemHandle) — 최신 API, Chromium 계열
- WebKit Entry API (webkitGetAsEntry) — 폴백
- 표준 File API (getAsFile) — 마지막 폴백
각 방식 모두 파일과 디렉토리를 구분하며, 디렉토리는 무시하고 파일만 처리합니다.
9. 언제 쓰나
FileDropUpload가 맞을 때
- 드래그앤드롭 UI가 주된 방식 — 대량 업로드 화면, 파일 관리 도구
- CSV/JSON 파일 파싱 (fileType: 'text')
- 이미지·문서 미리보기 (fileType: 'binary' → DataURL)
- 커스텀 UI가 필요한 업로드 영역 (자유도 높음)
다른 걸 쓸 때
- 표준 파일 선택 다이얼로그 → Va.File / Va.FileButton
- 이미지 미리보기 통합 → Va.ImageFile
- 라벨 붙은 폼 필드 → Va.FileDropUploadField
10. 흔한 조합 예시
// 표준 (바이너리, DataURL 반환)
{
tagName: 'fileDropUpload',
text: '파일을 여기 놓으세요',
fileType: 'binary',
style: {
width: '100%',
height: '200px',
border: '2px dashed var(--colorNeutralStroke)',
borderRadius: '8px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
cursor: 'pointer'
},
onFiledrop: 'onDrop'
}
// CSV 파싱용 (텍스트 읽기)
{
tagName: 'fileDropUpload',
text: 'CSV 파일을 놓으세요',
fileType: 'text',
onFiledrop: 'onCsvDrop'
}
// 아이콘 포함
{
tagName: 'fileDropUpload',
innerHTML: '<div style="text-align:center"><i class="ico_cloud_upload" style="font-size:48px"></i><br>파일을 드래그하거나 클릭하세요</div>',
fileType: 'binary'
}
// 여러 파일 동시 드롭 처리
{
tagName: 'fileDropUpload',
text: '이미지 여러 개를 드래그',
fileType: 'binary',
onChange: 'onMultiFiles'
}
11. 실전 예 — CSV 파일 파싱
class CsvImport extends Va.View {
onCsvDrop(comp, el, result, evt) {
// result는 파일의 전체 텍스트 내용
const lines = result.split('\n').filter(line => line.trim());
const headers = lines[0].split(',');
const data = [];
for (let i = 1; i < lines.length; i++) {
const values = lines[i].split(',');
const row = {};
headers.forEach((h, idx) => {
row[h.trim()] = values[idx]?.trim() || '';
});
data.push(row);
}
// 그리드에 반영
this.getRef('grid').setData(data);
new Va.Alert({
title: '완료',
message: `${data.length}건 로드됨`
}).show(this);
}
config() {
return {
tagName: 'page',
tags: [{
tagName: 'panel',
tags: [
{ tagName: 'h2', innerHTML: 'CSV 가져오기' },
{
tagName: 'fileDropUpload',
text: 'CSV 파일을 드래그하세요',
fileType: 'text',
style: {
width: '100%',
height: '150px',
border: '2px dashed gray',
borderRadius: '8px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
marginBottom: '20px'
},
onFiledrop: 'onCsvDrop'
},
{
tagName: 'grid',
ref: 'grid',
columns: [/* 동적 */]
}
]
}]
};
}
}
12. 실전 예 — 이미지 여러 개 업로드
class MultiImageUpload extends Va.View {
onMultiFiles(comp, el, files, evt) {
// files는 FileList — 여러 파일 처리
const gallery = this.getRef('gallery');
gallery.innerHTML = '';
for (let i = 0; i < files.length; i++) {
const file = files[i];
// 이미지만
if (!file.type.startsWith('image/')) continue;
// 각 이미지 미리보기 생성
const reader = new FileReader();
reader.onload = (e) => {
const img = document.createElement('img');
img.src = e.target.result;
img.style.width = '150px';
img.style.margin = '4px';
gallery.appendChild(img);
};
reader.readAsDataURL(file);
}
// 서버 전송
this.uploadFiles(files);
}
uploadFiles(files) {
const formData = new FormData();
for (let i = 0; i < files.length; i++) {
formData.append('images', files[i]);
}
this.showMasking();
UploadService.send(this, formData, (view, ok) => {
view.hideMasking();
});
}
config() {
return {
tagName: 'page',
tags: [{
tagName: 'panel',
tags: [
{
tagName: 'fileDropUpload',
text: '이미지 여러 개를 드래그하세요',
fileType: 'binary',
style: {
width: '100%',
height: '150px',
border: '2px dashed gray',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
},
onChange: 'onMultiFiles' // change 이벤트로 전체 files 받기
},
{
tagName: 'div',
ref: 'gallery',
style: { display: 'flex', flexWrap: 'wrap', marginTop: '20px' }
}
]
}]
};
}
}
포인트:
- 여러 파일: files 배열을 for-loop로 처리
- change 이벤트로 전체 목록 받음 (filedrop은 파일 하나씩 반복 호출)
- 각 파일 미리보기는 FileReader로 개별 처리
13. 알아두면 좋을 주의사항
- fileType 반드시 지정 — 미지정 시 Va.Alert로 경고. 'text' / 'binary' 중 선택.
- 'binary'는 실제로 DataURL — 진짜 ArrayBuffer 필요하면 별도 FileReader.readAsArrayBuffer 처리.
- filedrop은 파일마다 반복 — 여러 파일 드롭 시 각 파일에 대해 dispatch. 전체 목록은 change로.
- 디렉토리는 자동 무시 — 폴더 드롭해도 파일만 처리.
- 파일 다이얼로그 없음 — 클릭으로 파일 선택 창이 안 열림. 필요하면 component.fieldElement.click() 수동 호출로 UI 추가.
- 빨간 outline 하드코딩 — 시각 피드백 색상 변경은 CSS 커스터마이즈.
- 레이아웃/스타일 개발자 책임 — 기본 스타일 최소. height, border 등 스타일을 직접 지정해야 UI가 보임.
- getFiles() 편의 메서드 없음 — component.fieldElement.files 직접 접근.
- text/innerHTML 세팅 시 element에 직접 반영 — this.element.textContent = text로. inner에 반영되는 게 아니라 element 전체가 텍스트로 대체됨 (다른 컴포넌트와 다른 동작). ⚠️ 이 때문에 innerElement가 덮여 파일 input이 사라질 수 있는 버그 위험. text/innerHTML 사용 시 주의.
- 접근성 취약 — role="button"/aria-label 자동 세팅 없음. 스크린리더 대응 약함.
- 모바일 지원 제한 — 드래그앤드롭은 데스크톱 위주 UX.
- disabled 시 파일 input에 disable (오타)로 세팅 — va_component.js:12591에 disable(l 없음)로 표기. HTML 표준 disabled와 다름. 실질 disable 동작 확인 필요.
14. fileDropUpload vs imageFile vs file 선택
상황추천
| 드래그앤드롭 주 UI | fileDropUpload |
| CSV/JSON 파싱 | fileDropUpload + fileType: 'text' |
| 이미지 미리보기 통합 | imageFile |
| 표준 파일 첨부 | file / fileField |
| 간단 첨부 버튼 | fileButton |
| 여러 파일 대량 관리 UI | fileDropUpload + 커스텀 목록 |
"드래그앤드롭이 UI의 핵심이면 fileDropUpload" — 명확한 사용처.
참고
- API 문서 페이지: https://vanillafront.com/docs.html?theme=light#main#apifiledropupload
- 연관: Va.FileDropUploadField(라벨 포함 버전), Va.File(형제 파일 컴포넌트)
'컴포넌트 > 필드 컴포넌트' 카테고리의 다른 글
| Display (디스플레이) (0) | 2026.09.14 |
|---|---|
| FileDropUploadField (파일드롭 업로드 필드) (0) | 2026.09.14 |
| ImageFile (이미지파일) (1) | 2026.09.14 |
| FileField (파일필드) (1) | 2026.09.14 |
| File (파일) (0) | 2026.09.13 |