✨
追加してファイルをアップロード
ファイルを追加してアップロードできるようにjavascriptで処理します。
通常
普通に書いた場合、一度アップロードすると追加でファイルアップロードできず
上書きされます。
<input id="test" type="file">
これだと一度に複数選択できるが、連続してアップロードするとやはり上書きされます。
<input id="test" type="file" multiple>
やりたいこと
複数回連続してアップロードできるように
イベントリスナーを使ってファイルアップロードされたタイミングで
ファイル追加・更新できるようにします。
<script>
// 1. アップロードしたファイルを保持する変数を定義
const fileList = [];
// 2. イベントリスナーを定義
const upload = document.getElementById("test");
upload.addEventListener("change", (e) => {
const dt = new DataTransfer();
const uploaded = e.target.files;
// 3. アップロードしたファイルをいったん移築
fileList.forEach((file) => {
dt.items.add(file);
})
for (let i=0;i<uploaded.length;i++) {
dt.items.add(uploaded[i]);
// 4. アップロードしたファイルを保持
fileList.push(uploaded[i]);
}
// 5. もとにもどす
upload.files = dt.files;
})
</script>
連続してアップロードできるようにするため、
ドラッグアンドドロップで利用するDataTransfer()
を使います。
アップロードしたファイルを操作することができます。
アップロードはFileListでイベントで取得できますが、
配列のようにforEachは利用できません。
Array.from
を使うとforEachが使えます。
Array.from(uploaded).forEach(file => {
// 以下処理
})
html標準だと、1ファイルしかファイル名が表示されないため、
すべてのファイル名を表示するためには
カスタムする必要があります。
const names = document.getElementById("names");
const name = document.createElement("span");
upload.addEventListener("change", (e) => {
// 6. ファイル名を表示
name.textContent = fileList.map((file) => { return file.name }).join();
names.appendChild(name);
}
そのままだと
ファイルアップロードとフォントが違うので
inputタグを透明化して自作するとデザインが統一されてよさげです。
完成
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
*,
*::before,
*::after {
box-sizing: border-box;
}
:root {
--border_rgb_color: 206, 212, 218;
}
label {
position: relative;
display: inline-block;
padding: .4em 1em;
margin: 0 .5em 0 0;
border: 1px solid rgb(var(--border_rgb_color));
border-radius: .25em;
height: max-content;
}
input[type="file"] {
position: absolute;
opacity: 0;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.upload_block {
display: flex;
align-items: center;
}
.file_names span {
font-size: .80em;
}
</style>
<title></title>
</head>
<body>
<div class="upload_block">
<label>
<input type="file" name="" id="test" multiple>
<span>ファイルを選択</span>
</label>
<div id="names" class="file_names"></div>
</div>
<script>
const fileList = [];
const upload = document.getElementById("test");
const names = document.getElementById("names");
const name = document.createElement("span");
upload.addEventListener("change", (e) => {
const dt = new DataTransfer();
const uploaded = e.target.files;
fileList.forEach((file) => {
dt.items.add(file);
})
for (let i = 0; i < uploaded.length; i++) {
dt.items.add(uploaded[i]);
fileList.push(uploaded[i]);
}
name.textContent = fileList.map((file) => { return file.name }).join();
names.appendChild(name);
upload.files = dt.files;
})
</script>
</body>
</html>
まとめ
ファイル名表示は素のhtmlとjavascriptで書くより、フレームワーク使ったほうが
簡単だなと思いました。
アップロードしたファイルの一部削除もこれなら制御できるようになります。
Discussion