最近はファイルのアップロード画面にドラッグ&ドロップが当たり前のように実装されるようになりました。画面がブラウザから離れるのであまり好きなUIではないのですが、案件としてリクエストがあったので実装です。
ボタンを押した際に通常のファイル選択UIが表示されるようにし、かつドラッグ&ドロップ対応です。
プレビューや送信処理は記述せず、アップされたファイルのサイズとファイル情報だけ表示するものです。
目次
HTML
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ファイルアップロード</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="app">
<div class="file-upload">
<input type="file" ref="fileInput" @change="handleFileChange" class="file-input" style="display: none;">
<div class="drop-area" @dragover.prevent @drop="handleDrop">
<button @click="$refs.fileInput.click()" class="file-select-button">ファイルを選択</button>
ドラッグ&ドロップするか、ファイルを選択してください
</div>
</div>
<div class="file-preview" v-if="file">
<p><strong>選択したファイル:</strong> {{ file.name }}</p>
<p><strong>ファイルタイプ:</strong> {{ file.type }}</p>
<p><strong>ファイルサイズ:</strong> {{ formatSize(file.size) }}</p>
</div>
</div>
<script src="https://unpkg.com/vue@3.0.0/dist/vue.global.prod.js"></script>
<script src="app.js"></script>
</body>
</html>
JavaScript(Vue)
app.js
const app = Vue.createApp({
data() {
return {
file: null,
};
},
methods: {
handleFileChange(event) {
const selectedFile = event.target.files[0];
this.file = selectedFile;
},
handleDrop(event) {
event.preventDefault();
const droppedFile = event.dataTransfer.files[0];
this.file = droppedFile;
},
formatSize(bytes) {
const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
if (bytes === 0) return "0 Byte";
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return Math.round(bytes / Math.pow(1024, i), 2) + " " + sizes[i];
},
},
});
app.mount("#app");
CSS
styles.css
body {
font-family: Arial, sans-serif;
text-align: center;
background-color: #f0f0f0;
}
.file-upload {
margin: 20px;
}
.file-input {
display: none;
}
.drop-area {
border: 2px dashed #ccc;
padding: 20px;
cursor: pointer;
background-color: #fff;
}
.file-preview {
background-color: #fff;
margin: 20px;
padding: 10px;
border: 1px solid #ccc;
}