๐ 1.type="file"
HTML์์ <input type="file"> ์์๋ ์ฌ์ฉ์๊ฐ ๋ก์ปฌ ์ปดํจํฐ์์ ํ์ผ์ ์ ํํด ์๋ฒ๋ก ์ ๋ก๋ํ ์ ์๊ฒ ํ๋ ์ ๋ ฅ ํ๋๋ค.

file ์ ๋ ฅ ํ๋์ ๋ค์ด๊ฐ๋ ๋ฐ์ดํฐ๋ FileList ๊ฐ์ฒด๋ก input[type="file"].files๋ฅผ ํธ์ถํ๋ฉด FileList ๊ฐ์ฒด๊ฐ ๋ฐํ๋๋ค.
โ ๋์ ์๋ฆฌ
1๏ธโฃ html์ ๊ธฐ๋ณธ ์์ ์ค ํ๋์ธ file ์์๋ ํด๋ฆญ ์ ๋ก์ปฌ ํ์ผ ํ์๊ธฐ ์ฐฝ์ ์ด๊ณ ,
2๏ธโฃ ํ์ผ์ ์ ํํ๋ฉด, <input> ์์์ ๊ฐ์ด ํ์ผ ๊ฐ์ฒด๋ก ์ฑ์์ง๋ค.
3๏ธโฃ ํผ ์ ์ถ ์, ํ์ผ์ด multipart/form-data ํ์์ผ๋ก ์๋ฒ์ ์ ์ก๋๋ค.
<input type="file" id="fileInput" multiple>
โ ๏ธ ์ฃผ์:
<form> ํ๊ทธ์ enctype์ด ๋ฐ๋์ multipart/form-data๋ก ์ง์ ๋์ด์ผ ํ์ผ์ด ์ ์ก๋๋ค.
<form enctype="multipart/form-data">
๐ 2. DataTransfer์ ์ด์ฉํ ์ปค์คํ
์ปค์คํ ํ๋ ค๋ฉด DataTransfer ๊ฐ์ฒด๋ฅผ ํ์ฉํด ํ์ผ ๋ชฉ๋ก์ ๊ด๋ฆฌํ๊ณ , file ํผ์ ํ์ผ ์ ํ์ฐฝ๋ง ์ด ๋๋ง ์ฌ์ฉํ๋ฉด๋๋ค.
๐ ์ปค์คํ ๊ธฐ๋ฅ ์์
๐น ์ปค์คํ
UI: ์ ํํ ํ์ผ์ ๋ฆฌ์คํธ๋ก ๋ณด์ฌ์ฃผ๊ณ , ์ญ์ ๋ฒํผ์ ์ถ๊ฐํ ์ ์์.
๐น ์๋ฒ ์ฐ๋: ํ์ผ์ ์
๋ก๋ํ ํ, ์๋ฒ์์ ์ญ์ /์์ API๋ฅผ ํธ์ถํ ์ ์์.
๐น ํ์ผ ์ ํ์ฐฝ ์ฌ์ฉ: file ์
๋ ฅ ํ๋๋ ๋จ์ํ ํ์ผ์ ์ถ๊ฐํ๋ ์ญํ ๋ก๋ง ์ฌ์ฉ.
๐ ์์
const dt = new DataTransfer();
dt.items.add(new File(["content"], "example.txt")); // ํ์ผ ์ถ๊ฐ
document.querySelector("input[type=file]").files = dt.files; // ํ์ผ ํ๋์ ์ ์ฉ
โ UI์์ ํ์ผ ์ญ์ ์ DataTransfer.items.remove()๋ฅผ ํ์ฉ!
๐ ์์ (์ปค์คํ UI + DataTransfer ํ์ฉ)
<input type="file" id="fileInput" multiple hidden>
<button onclick="document.getElementById('fileInput').click()">ํ์ผ ์ ํ</button>
<ul id="fileList"></ul>
const fileInput = document.getElementById("fileInput");
const fileList = document.getElementById("fileList");
let dt = new DataTransfer();
fileInput.addEventListener("change", (e) => {
for (const file of e.target.files) {
dt.items.add(file);
const li = document.createElement("li");
li.textContent = file.name;
const btn = document.createElement("button");
btn.textContent = "์ญ์ ";
btn.onclick = () => {
dt.items.remove([...dt.files].indexOf(file));
fileInput.files = dt.files;
li.remove();
};
li.appendChild(btn);
fileList.appendChild(li);
}
fileInput.files = dt.files;
});
๐ 3. ํ์ผ ์์ , ์ญ์ ๊ธฐ๋ฅ
๋ณดํต ์ฒจ๋ถํ์ผ ๊ธฐ๋ฅ์์ ๊ธฐ์กด ํ์ผ๋ฆฌ์คํธ๋ฅผ ๊ฐ์ง ๊ฐ์ฒด ํํ (์ด๋ฆ, ์ฉ๋๋ง ํ์)๋ก ๋ค๊ณ ์์ ui์ ๋ณด์ฌ์ค๋ค.
๊ทธ๋ฆฌ๊ณ ์ด์ ๋ํ ์์ , ์ญ์ ๊ธฐ๋ฅ๋ ์ ๊ณตํ๊ธฐ์ํด์ ํ๋ก ํธ์์ ํ์ผ ๋ฆฌ์คํธ๋ฅผ ๋ฐ๋ก ๊ด๋ฆฌํด์ผํ๋ค. (๋ฐฑ์๋์์ ์ฒ๋ฆฌํ ์๋ ์๊ธดํ๋ค.)
๐ ํ์ผ ์์ ๊ธฐ๋ฅ์์ ํ์ํ ๋ชฉ๋ก 3๊ฐ์ง
1๏ธโฃ newFileDT (์๋ก ์ถ๊ฐ๋ ํ์ผ ๋ฆฌ์คํธ) → DataTransfer ๊ฐ์ฒด๋ก ๊ด๋ฆฌ
2๏ธโฃ deleteList (์ญ์ ํ ๊ธฐ์กด ํ์ผ ๋ฆฌ์คํธ) → ๋ฐฐ์ด([])๋ก ๊ด๋ฆฌ
3๏ธโฃ keepList (์ ์งํ ๊ธฐ์กด ํ์ผ ๋ฆฌ์คํธ) → ๊ธฐ์กด ํ์ผ์์ deleteList๋ฅผ ์ ์ธํ ๋๋จธ์ง
๐ ์ ์ฒด ํ๋ฆ
- ๊ธฐ์กด ํ์ผ(existingFiles)์ UI์ ํ์.
- ์ฌ์ฉ์๊ฐ ์ ํ์ผ์ ์ถ๊ฐํ๋ฉด newFileDT์ ์ ์ฅ.
- ๊ธฐ์กด ํ์ผ์ ์ญ์ ํ๋ฉด deleteList์ ์ถ๊ฐ.
- ์ ์ก ์ keepList๋ ๊ธฐ์กด ํ์ผ์์ deleteList๋ฅผ ์ ์ธํ ๋๋จธ์ง.
๐ HTML ๊ตฌ์กฐ
<input type="file" id="fileInput" multiple hidden>
<button onclick="document.getElementById('fileInput').click()">ํ์ผ ์ ํ</button>
<ul id="fileList"></ul>
<button onclick="submitFiles()">์
๋ก๋</button>
๐ JavaScript ์ฝ๋
const fileInput = document.getElementById("fileInput");
const fileList = document.getElementById("fileList");
// ๊ธฐ์กด ํ์ผ ๋ชฉ๋ก (DB์์ ๋ถ๋ฌ์จ ํ์ผ)
let existingFiles = ["old1.pdf", "old2.jpg"];
let deleteList = []; // ์ญ์ ํ ํ์ผ ๋ชฉ๋ก
let newFileDT = new DataTransfer(); // ์๋ก ์ถ๊ฐํ ํ์ผ ๋ชฉ๋ก
let keepList = [...existingFiles]; // ์ ์งํ ๊ธฐ์กด ํ์ผ ๋ชฉ๋ก (์ด๊ธฐ๊ฐ = ๊ธฐ์กด ํ์ผ)
// ๊ธฐ์กด ํ์ผ UI ํ์
existingFiles.forEach(fileName => addFileToUI(fileName, false));
// ํ์ผ ์ถ๊ฐ ์ด๋ฒคํธ
fileInput.addEventListener("change", (e) => {
for (const file of e.target.files) {
newFileDT.items.add(file);
addFileToUI(file.name, true);
}
fileInput.files = newFileDT.files;
});
// ํ์ผ์ UI์ ์ถ๊ฐํ๋ ํจ์
function addFileToUI(fileName, isNew) {
const li = document.createElement("li");
li.textContent = fileName;
const btn = document.createElement("button");
btn.textContent = "์ญ์ ";
btn.onclick = () => {
if (isNew) {
// ์ ํ์ผ ์ญ์ : DataTransfer์์ ์ ๊ฑฐ
const index = [...newFileDT.files].findIndex(f => f.name === fileName);
if (index > -1) {
newFileDT.items.remove(index);
fileInput.files = newFileDT.files;
}
} else {
// ๊ธฐ์กด ํ์ผ ์ญ์ : ์ญ์ ๋ฆฌ์คํธ์ ์ถ๊ฐํ๊ณ ์ ์ง ๋ฆฌ์คํธ์์ ์ ๊ฑฐ
deleteList.push(fileName);
keepList = keepList.filter(f => f !== fileName);
}
li.remove();
};
li.appendChild(btn);
fileList.appendChild(li);
}
// ํ์ผ ์ ์ก ํจ์
function submitFiles() {
console.log("โ
์ ์งํ ๊ธฐ์กด ํ์ผ ๋ชฉ๋ก:", keepList);
console.log("โ ์ญ์ ํ ํ์ผ ๋ชฉ๋ก:", deleteList);
console.log("โ ์๋ก ์ถ๊ฐํ ํ์ผ ๋ชฉ๋ก:", newFileDT.files);
// ๐น ์๋ฒ๋ก ์ ์กํ๋ ๋ก์ง ์ถ๊ฐ ๊ฐ๋ฅ (AJAX ๋๋ FormData ํ์ฉ)
}
๐ ์ ๋ฆฌ
โ ์ ์งํ ๊ธฐ์กด ํ์ผ(keepList) = existingFiles - deleteList
โ ์ญ์ ํ ํ์ผ(deleteList) = ์ฌ์ฉ์๊ฐ ์ญ์ ํ ๊ธฐ์กด ํ์ผ ๋ชฉ๋ก
โ ์๋ก ์ถ๊ฐ๋ ํ์ผ(newFileDT) = file ์
๋ ฅ ํ๋์์ ์ถ๊ฐํ ํ์ผ ๋ชฉ๋ก
โ ์๋ฒ ์ ์ก ์ 3๊ฐ์ง ๋ฆฌ์คํธ๋ฅผ ๋ณ๋๋ก ๊ด๋ฆฌํ๋ฉด ๊น๋ํ๊ฒ ์ฒ๋ฆฌ ๊ฐ๋ฅ!
'Frontend > javaScript' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| summernote - ์๋ํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ (0) | 2025.08.31 |
|---|---|
| JavaScript ๋ชจ๋ ์ฌ์ฉ (0) | 2025.04.06 |
| JavaScript ์ฝ๋ ์คํ ์์ & ์คํ ํ์ด๋ฐ ์ ์ด (0) | 2025.04.06 |
| [JavaScript] ํธ์ด์คํ (Hoisting) (0) | 2024.07.05 |
| iframe sesstion timeout (0) | 2023.10.13 |