前置き
input type="file"
で
選択した画像をFirebase Cloud Storageに
送信&取得をしていきます🌸
⬇️firebaseのプロジェクト作成などは
こちらをご覧ください👀
Databaseではなく
Storageを使っています💫
【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
を使う、
とイメージする方が多いと思います💡
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<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="input"
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
<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
を
詳しく見ていきましょう💡
1 2 3 4 5 6 7 |
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に入れた画像を表示させる
取得と送信用の画像データを
分かりやすくするために
新しくdata postData thumbnail
を作成。FileReader
を使って
画像情報を表示させています。readAsDataURL
で
送信用のURLデータに変換しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
<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> 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) } }, submitImg () { // ここでsubmitする }, }, } </script> <style lang="scss" scoped> </style> |
FileReader + firebase
送信
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
<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
した時のエラー。
Error
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')などの子を使用して非ルート参照を作成してください。 (ストレージ/無効なルート操作)
ということで
非ルート参照にする必要があるようです。
取得
getDownloadURL()
を使用します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
<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の変数の末尾の"!"(エクスクラメーション/感嘆符)の意味