概要
HTMLフォームで入力途中の情報を localStorage に保存し、再開時に情報を復元して最終的に Ajax で POST するまでを実装しました。
その際、ファイルアップロードだけ少し厄介だったので要点をまとめました。
Internet Explorer 11 でもうまく行きました。
※ Vue.js で元々実装していたものを無理矢理素の JavaScript に書き直しており、うまく動作しない部分があったらすみません。
アップロードされたファイルを変数で保持する
// この変数にアップロードファイルの情報を格納することにする
var file = null
// この変数にアップロードファイルをデータURI化した情報を格納することにする
var uri = null
// ファイルアップロード時に呼ばれるイベントハンドラー
function (e) {
file = e.target.files[0]
var reader = new FileReader()
reader.onload = function (e) {
uri = e.target.result
}
reader.readAsDataURL(file)
}
アップロードファイルを localStorage に保存
// アップロードファイル名
localStorage.setItem('name', file.name)
// ファイル種別
localStorage.setItem('type', file.type)
// ファイルのデータURI
localStorage.setItem('uri', uri)
アップロードファイルを localStorage から復元
// この変数にアップロードファイルの情報を復元することにする
var file = null
// この変数にアップロードファイルをデータURI化した情報を復元することにする
var uri = localStorage.getItem('uri')
// アップロードファイルを復元する。
var binary = atob(
uri.slice(value.answer.file.indexOf(',') + 1)
)
var bytes = new Uint8Array(binary.length)
for (var i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i)
}
file = new Blob([bytes], {
type: localStorage.getItem('type'),
})
file.name = localStorage.getItem('name')
なお、 Vuetify
を使っている場合、v-file-input
の v-model
に上記 fileをセットしてあげると、ファイルの選択状態まで復元できました。
アップロードファイルを POST する
Axios で POSTする例
import Axios from 'axios'
var formData = new FormData()
formData.append('file', file, file.name)
Axios.post('/url', formData, { headers: { 'Content-Type': 'multipart/form-data' } })
今回使った復元方法だと、元々 File
クラスだったものを Blob
クラスとして復元しており、その影響で
formData.append()
の第3引数を無しにしてしまうとファイル名が渡らないという問題があり、第3引数が必要でした。
今回はAjaxでPOSTしましたが、Ajaxではなくformタグのsubmit機能を使って復元したファイルをPOSTするのは、セキュリティ的な問題で難しそうです。
余談1 アップロードされた画像を表示する
画像がアップロードされた場合、以下のコードでアップロードされた画像を表示できます。
<img src="" id="img" />
// ~~略~~
document.getElementById('img').src = uri
余談2 アップロードされたファイルのダウンロードリンクを生成する
画像以外がアップロードされた場合、以下のコードでアップロードファイルのダウンロードリンクを生成できます。Internet Explorer 11の場合、ちょっと工夫が必要でした。
<a href="" download id="download" onclick="download()">アップロードされたファイル</a>
// ~~略~~
var download = function() {
if (!window.navigator.msSaveBlob) {
return true
}
// IE, Edgeの場合は特殊な処理を行いダウンロードできるようにする
var type = uri.match(/^data:(.*);base64,/, function() {
return RegExp.$1
})[1]
var bin = atob(bfile.replace(/^.*,/, ''))
var buff = new Uint8Array(bin.length)
for (var i = 0; i < bin.length; i++) {
buff[i] = bin.charCodeAt(i)
}
var blob = new Blob([buff.buffer], { type: type })
window.navigator.msSaveBlob(blob, file.name)
return false
}