LoginSignup
1
2

More than 3 years have passed since last update.

【Nuxt.js】firebase基礎編:Cloud Storageで画像アップロード&取得

Posted at

🎈 この記事はWP専用です
https://wp.me/pc9NHC-Xy

前置き

⬇️プロジェクトページ
image.png
⬇️Firebase Storage画面
image.png

input type="file" で
選択した画像をFirebase Cloud Storageに
送信&取得をしていきます🌸

⬇️firebaseのプロジェクト作成などは
 こちらをご覧ください👀
 【Nuxt.js】firebase導入編(RDB版):データの追加 取得をしよう

公式: Cloud Storage

参考:
FirebaseStorageの使い方・Singleを使って実装する。
Vue/Vuex/Nuxtのformでinput type='file'を指定するとv-modelが使えない
firebase Storageへのファイル保存
File APIとFileReader APIの利用

firebaseを使う前に

input type="file"でv-modelは使えない

Nuxtのテンプレートでは
inputにv-modelを使う、
とイメージする方が多いと思います💡

index.vue
<template>
  <div class="page">
    <form
      class="form"
      @submit.prevent="submitImg"
    >
      <input
        // ここがエラーになります
        v-model="image"
        type="file"
      >
      <button
        type="submit"
        class="button"
      >
        click
      </button>
    </form>
  </div>
</template>

しかしv-modelは
type="file"のサポートをしておりません🌀

@changeを使う

v-modelの代わりに
@changeを使用します。

submitの前に、
@change
選択した画像の
Fileオブジェクトを
確認しています👀

e.target.files[0]
選択ファイルを配列形式で取得
まぁ画像のタイトルとかの情報が
入ってるものです💫

eventのtargetには「files」というプロパティが用意されています。これは「FileList」という複数ファイルを管理するオブジェクトが設定されています。このFileListでは、配列のようにファイルが管理されているのです。
http://libro.tuyano.com/index3?id=384001&page=2

image.png

index.vue
<template>
  <div class="page">
    <form
      class="form"
      @submit.prevent="submitImg"
    >

      <input
        type="file"
        accept="img/*"
        @change="changeImg"
      >
      <button
        type="submit"
        class="button"
      >
        click
      </button>
    </form>
  </div>
</template>


<script>
export default {
  data () {
    return {
      thumbnail: '',
    }
  },
  methods: {
    changeImg (e) {
      this.thumbnail = e.target.files[0]
      console.log(this.thumbnail)
    },
    submitImg () {
      // ここでsubmitする
    },
  },
}
</script>

<style lang="scss" scoped>
</style>

firebaseの確認

put()メソッドで送信

送信にはput()メソッドを使います。
引数にはFileまたはBlobインスタンスを
指定する必要があるようです。
Upload from a Blob or File

今回はFileオブジェクトの読み込みをする
FileReader APIを使用します。
APIといっても
元から使用できるので
axiosを使う必要はありません💫☝️

submitのコードイメージは
こんな感じですね。
ということで
次のFileReaderを
詳しく見ていきましょう💡

index.vue
submitImg () {
      let storage = firebase.storage()
      let storageRef = storage.ref().child('file.png')
      storageRef.put([FileReaderAPIを使用したファイル])
        .then(res => console.log(res))
        .catch(error => console.log(error))
},

FileReaderの確認

new FileReader()
fileを実際に読み込みます

readAsDataURL
fileをURLデータに変換する

onload
読み込みが成功、完了

result
読み込み結果

inputに入れた画像を表示させる

image.png

取得と送信用の画像データを
分かりやすくするために
新しくdata postData thumbnailを作成。
FileReaderを使って
画像情報を表示させています。
readAsDataURLで
送信用のURLデータに変換しています。

index.vue
取得と送信用の画像データを
分かりやすくするために
新しくdata postData thumbnailを作成。
FileReaderを使って
画像情報を表示させています。
readAsDataURLで
送信用のURLデータに変換しています。

FileReader + firebase

送信

index.vue
<template>
  <div class="page">
    <form
      class="form"
      @submit.prevent="submitImg()"
    >
      <input
        type="file"
        accept="img/*"
        @change="changeImg"
      >
      <button
        type="submit"
        class="button"
      >
        click
      </button>
   </form>
    <div>
      <p>{{ thumbnail }}</p>
      <p>{{ postData.thumbnail }}</p>
      <img :src="postData.thumbnail" alt="">
    </div>
  </div>
</template>

<script>
import firebase from '@/plugins/firebase'

export default {
  data () {
    return {
      thumbnail: '',
      postData: {
        thumbnail: '',
      },
    }
  },
  methods: {
    changeImg (e) {
      this.thumbnail = e.target.files[0]

      if (this.thumbnail) {
        const reader = new FileReader()
        reader.onload = () => {
          this.postData.thumbnail = reader.result + ''
        }
        reader.readAsDataURL(this.thumbnail)
        console.log('選択完了')
        this.submitImg(this.thumbnail)
      }
    },
    submitImg (thumbnail) {
      let storage = firebase.storage()
      let storageRef = storage.ref().child('file.png')
      storageRef.put(thumbnail)
        .then(res => console.log(res))
        .catch(error => console.log(error))
    },
  },
}
</script>

<style lang="scss" scoped>
</style>

送信時に起きたエラー

とりあえずchildとか使わずに
firebase.storage().ref()に
putした時のエラー。
⬇️
FirebaseError: Firebase Storage: The operation 'put' cannot be performed on a root reference, create a non-root reference using child, such as .child('file.png'). (storage/invalid-root-operation)

翻訳

FirebaseError:Firebase Storage:操作 'put'はルート参照に対して実行できません。.child( 'file.png')などの子を使用して非ルート参照を作成してください。 (ストレージ/無効なルート操作)


ということで
非ルート参照にする必要があるようです。

取得

Download Data via URL

getDownloadURL()を使用します。

index.vue
<template>
  <div class="page">
    <form
      class="form"
      @submit.prevent="submitImg()"
    >
      <input
        type="file"
        accept="img/*"
        @change="changeImg"
      >
      <button
        type="submit"
        class="button"
      >
        click
      </button>
      <div>
        <p>{{ thumbnail }}</p>
        <p>{{ postData.thumbnail }}</p>
        <img :src="postData.thumbnail" alt="">
      </div>
    </form>
    <div>
      <button
        class="button"
        @click="getImg()"
      >
        取得
      </button>
      <img :src="getData.thumbnail" alt="">
    </div>
  </div>
</template>

<script>
import firebase from '@/plugins/firebase'

export default {
  data () {
    return {
      thumbnail: '',
      postData: {
        thumbnail: '',
      },
      getData: {
        thumbnail: '',
      },
    }
  },
  methods: {
    changeImg (e) {
      this.thumbnail = e.target.files[0]

      if (this.thumbnail) {
        const reader = new FileReader()
        reader.onload = () => {
          this.postData.thumbnail = reader.result + ''
        }
        reader.readAsDataURL(this.thumbnail)
        console.log('選択完了')
        this.submitImg(this.thumbnail)
      }
    },
    submitImg (thumbnail) {
      let storage = firebase.storage()
      let storageRef = storage.ref().child('file.png')
      storageRef.put(thumbnail)
        .then(res => console.log(res))
        .catch(error => console.log(error))
    },
    getImg () {
      let storage = firebase.storage()
      let storageRef = storage.ref().child('file.png')
      storageRef.getDownloadURL()
        .then(res => {
          console.log(res)
          this.getData.thumbnail = res
        })
    },
  },
}
</script>

<style lang="scss" scoped>
</style>

まとめ

firebaseは公式ガイドをしっかり見れば
基礎的なことはできてきます🎈🧸
まだよく分からないという方は
こちらの記事で慣れましょう🌟
Firebase Realtime Database
Cloud Firestore

余談ですがQiitaの他に
GitHubでTSのコードを
参考にしました。
TS独自の書き方に慣れたいです💭
TSできれば無駄なチェックが不要になるし…

変数の後ろのびっくりマーク❗️の意味を知りました💡
TypeScriptの変数の末尾の"!"(エクスクラメーション/感嘆符)の意味

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