LoginSignup
6
6

More than 3 years have passed since last update.

アップロードファイルを localStorage に保存して、再アクセス時にファイルを復元する

Last updated at Posted at 2020-09-10

概要

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-inputv-model に上記 fileをセットしてあげると、ファイルの選択状態まで復元できました。

screenshot.png

アップロードファイルを 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 アップロードされた画像を表示する

画像がアップロードされた場合、以下のコードでアップロードされた画像を表示できます。

vue.js
<img src="" id="img" />
// ~~略~~
document.getElementById('img').src = uri

余談2 アップロードされたファイルのダウンロードリンクを生成する

画像以外がアップロードされた場合、以下のコードでアップロードファイルのダウンロードリンクを生成できます。Internet Explorer 11の場合、ちょっと工夫が必要でした。

vue.js
<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
}
6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6