経緯
ドラッグ&ドロップ式 ファイルアップロード画面のIE対応でハマった話
モダンブラウザではきちんと動くのに、edgeとIE11だけドロップしても動かない。
// input要素
const fileInput = document.getElementById("fileInput")
// ファイルをdropする要素
const dropTarget = document.getElementById("dropTarget")
function hoge(event) {
event.preventDefault()
event.stopPropagation()
event.dataTransfer.dropEffect = 'copy'
}
function fuga(event) {
event.stopPropagation()
event.preventDefault()
fileInput.files = event.dataTransfer.files; //今回問題の部分
}
dropTarget.addEventListener('dragover', e => {
hoge(e)
})
dropTarget.addEventListener('drop', e => {
fuga(e)
})
よくあるドラッグ&ドロップでフォーム実装する時の処理ですね。
<input type="file">
のFileListオブジェクトに対して、
なぜかIE系だけevent.dataTransfer.files
が入らない。
これに結構ハマりました。
対応
何やらIEからは「厳密モードのFileListは読み取り専用なので代入できません」って怒られます。
babelが吐き出してくれるソースにはデフォルトでuse strict
が付くので、取っちゃおうかと考えました。
{
"sourceType": "script"
}
"sourceType": "script"
を.babelrc
に追加することで、
バベられた後のソースからuse strict
を取っ払うことができます。
しかしこの対応でも動かない。
しかも"sourceType": "script"
を指定すると
import/exportがつかえなくなります。(しんどい)
何よりuse strict
を取るって対応そのものが単純に敗北感が強い。
解決
色々調べましたが、結局あまりスマートな解決の糸口が見つからず、
event.dataTransfer.files
を<input type="file">
の
FileListオブジェクトに突っ込まない方法で解決。
// input要素
const fileInput = document.getElementById("fileInput")
// 画像をdropする要素
const dropTarget = document.getElementById("dropTarget")
function piyo(data) {
const formData = new FormData(document.getElementById("form"))
formData.append('image', fileData[0])
//APIコール用のロジック
}
function hoge(event) {
event.preventDefault()
event.stopPropagation()
event.dataTransfer.dropEffect = 'copy'
}
function fuga(event) {
event.stopPropagation()
event.preventDefault()
piyo(event.dataTransfer.files);
}
dropTarget.addEventListener('dragover', e => {
hoge(e)
})
dropTarget.addEventListener('drop', e => {
fuga(e)
})
event.dataTransfer.files
を引数で渡していって
formdataに突っ込んでAPIに投げてあげる形に。
formdataがFilelistオブジェクトしか受け付けない。
みたいになってたら詰んでました。
File()
で新しくインスタンス生成する方向でも考えたものの、
第二引数に渡すBlob型のデータをdropで取得する方法がわからないのと、
普通にクリック処理でファイルを受け取る場合は
<input type="file">
のデフォルトの挙動に頼っていたので断念。
これ上手なやり方ご存知の方はぜひ教えてください。