1
1

More than 1 year has passed since last update.

v-file-inputでファイル選択をキャンセルするとv-modelが空になってしまう問題に対処してみる

Last updated at Posted at 2021-11-16

v-file-inputでファイル選択後にもう一度選択画面を開き、「キャンセル」をクリックするとmodelが空になってしまう問題に諸般の事情で対処してみた。

<template>
  <v-file-input
    label="ファイル選択"
    @change="loadFile"
    :clearable = false
    v-model="fileName"
  ></v-file-input>
</template>
<script>
  data () {
    return {
      fileName: null,
    }
  },
  methods: {
    loadFile(e) {
      if(e != null && e != undefined){
        const file = e
        let reader = new FileReader()
        reader.readAsText(file)
        reader.onload = () => {
          this.loadedFunction(reader.result)
        }
      } 
    },
    loadedFunction () {
      //ロード後の処理
    }
  }
</script>

だいたい上記のような実装になると思う。
これにキャンセル対策を施してみる。

<template>\
  <v-file-input
    label="ファイル選択"
    @change="loadFile"
    :clearable = false
    v-model="fileData"
  ></v-file-input>
</template>
<script>
  data () {
    return {
      fileData: null,
      //退避させる変数を用意
      prevFileData: null,
    }
  },
  methods: {
    loadFile(e) {
      if(e != null && e != undefined){
        const file = e
        let reader = new FileReader()
        reader.readAsText(file)
        reader.onload = () => {
          // 正常に読み込まれた場合、そのデータを保存しておく
          this.prevFileData = e
          this.loadedFunction(reader.result)
        }
      } else {
        //キャンセルされたときの処理
        let reader = new FileReader()
        //保存しておいたFileオブジェクトからBlobに変換、Fileオブジェクトにすることで参照渡しではなくコピーする
        reader.readAsDataURL(this.prevFileData)
        reader.onload = () => {
          let blob = this.dataURItoBlob(reader.result)
          let file = new File([blob], this.prevFileData.name, { type:this.prevFileData.type, lastModified:this.prevFileData.lastModified })
          //v-modelへ反映する
          this.fileData= file

        }
      }
    },
    loadedFunction () {
      //ロード後の処理
    }
    //dataURIをBlobに変換する関数
    dataURItoBlob(dataURI) {
      let byteString = atob(dataURI.split(',')[1])

      let mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

      let ab = new ArrayBuffer(byteString.length);
      let ia = new Uint8Array(ab);
      for (let i = 0; i < byteString.length; i++) {
          ia[i] = byteString.charCodeAt(i);
      }
      return new Blob([ab], {type: mimeString});
    },
  }

</script>

要はv-model以外に退避させておいてキャンセルだったらv-modelに退避させておいたデータを反映させるというやり方。
なんだかリソース食うなーという感じ。

これが正しいのかどうかわかりませんけど一応。

1
1
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
1
1