🎈 この記事はWP専用です
https://wp.me/pc9NHC-Xy
#前置き
⬇️プロジェクトページ
⬇️Firebase Storage画面
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を使う、
とイメージする方が多いと思います💡
<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
<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を
詳しく見ていきましょう💡
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データに変換しています。
取得と送信用の画像データを
分かりやすくするために
新しくdata postData thumbnailを作成。
FileReaderを使って
画像情報を表示させています。
readAsDataURLで
送信用のURLデータに変換しています。
#FileReader + firebase
##送信
<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')などの子を使用して非ルート参照を作成してください。 (ストレージ/無効なルート操作)
…
ということで
非ルート参照にする必要があるようです。
getDownloadURL()を使用します。
<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の変数の末尾の"!"(エクスクラメーション/感嘆符)の意味