前置き
以前の記事を
役割で切り分けて
Vuex版にしたコードです。
【Nuxt.js】firebase基礎編:Cloud Storageで画像アップロード&取得
この2つが
一緒になっていて
分かりにくかったので
切り分けてみました✂︎
・選択した画像を送信する
・url化してプレビューする
Vuexに移行する必要があるのは
送信と取得の部分です。
Step1: 送信するコードを考える
Vuexに移行する前のコード
選択した画像を
そのままstorageに
putすればOK🙆♀️
put
するため
引数にFile
を使用します💫
e.target.filesFileList
オブジェクトは
配列のように管理されていて
0番目に画像データが入っています。
それをそのまま送信📤
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 |
<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> </div> </form> </div> </template> <script> import firebase from '@/plugins/firebase' export default { data () { return { thumbnail: '', } }, methods: { changeImg (e) { this.thumbnail = e.target.files[0] console.log(this.thumbnail) if (this.thumbnail) { 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> |
Vuex移行後のコード
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 |
<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> </div> </form> </div> </template> <script> export default { data () { return { thumbnail: '', } }, methods: { changeImg (e) { this.thumbnail = e.target.files[0] }, submitImg (thumbnail) { this.$store.dispatch('submit', this.thumbnail) }, } </script> <style lang="scss" scoped> </style> |
1 2 3 4 5 6 7 8 9 10 11 |
import firebase from '@/plugins/firebase' export const actions = { submit ({ context }, image) { let storage = firebase.storage() let storageRef = storage.ref().child('file.png') storageRef.put(image) .then(res => console.log(res)) .catch(error => console.log(error)) }, } |
Step2: プレビューするコードを書き足す
Vuexに移行する必要がないので
付け足します✍️
画像を読み込みFile
オブジェクトをreadAsDataURL
でurlにします💫readAsDataURL
での
読み込みが完了したらonload
で結果をpostData.thumbnail
に入れます。
MDN: FileReader.onload
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 |
<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> <img :src="postData.thumbnail" alt=""> </div> </form> </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.readAsDataURL(this.thumbnail) reader.onload = () => { this.postData.thumbnail = reader.result + '' } } }, submitImg (thumbnail) { this.$store.dispatch('submit', this.thumbnail) }, } </script> <style lang="scss" scoped> </style> |
store
の変更はありません。
Step3: 取得するコードを考える
これで完成です🎶👏
取得の場合は
firestorageで取得した画像をgetDownloadURL
で
url化できるので
それをそのままstate
に入れます。
computed
で
urlをgettersで呼び出してimg src
にバインドさせればOKです✨
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 |
<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> <img :src="postData.thumbnail" alt=""> </div> </form> <div> <button class="button" @click="getImg" > 取得 </button> <img :src="getThumbnail" alt=""> </div> </div> </template> <script> export default { data () { return { thumbnail: '', postData: { thumbnail: '', }, } }, computed: { getThumbnail () { return this.$store.getters['thumbnail'] }, }, methods: { changeImg (e) { this.thumbnail = e.target.files[0] if (this.thumbnail) { const reader = new FileReader() reader.readAsDataURL(this.thumbnail) reader.onload = () => { this.postData.thumbnail = reader.result + '' } } }, submitImg () { this.$store.dispatch('submit', this.thumbnail) }, getImg () { this.$store.dispatch('getImg') }, }, } </script> <style lang="scss" scoped> </style> |
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 |
import firebase from '@/plugins/firebase' export const state = () => ({ thumbnail: '', }) export const getters = { thumbnail: state => { return state.thumbnail }, } export const actions = { submit ({ context }, image) { let storage = firebase.storage() let storageRef = storage.ref().child('file.png') storageRef.put(image) .then(res => console.log(res)) .catch(error => console.log(error)) }, getImg ({ commit }) { let storage = firebase.storage() let storageRef = storage.ref().child('file.png') storageRef.getDownloadURL() .then(res => { console.log(res) commit('getData', res) }) }, } export const mutations = { getData (state, image) { state.thumbnail = image }, } |
調整
見にくいので少しCSSを調整🎨
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 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
<template> <div class="page"> <form class="form" @submit.prevent="submitImg" > <label class="label"> <input type="file" accept="img/*" class="input" @change="changeImg" > </label> <div class="img"> <img v-show="postData.thumbnail" :src="postData.thumbnail" alt="preview" class="preview" > </div> <button type="submit" class="button" > <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 12l11 3.1 7-8.1-8.156 5.672-4.312-1.202 15.362-7.68-3.974 14.57-3.75-3.339-2.17 2.925v-.769l-2-.56v7.383l4.473-6.031 4.527 4.031 6-22z"/></svg> </button> </form> <div class="getImg"> <button class="button" @click="getImg" > getImg! </button> <div class="img"> <img v-show="getThumbnail" :src="getThumbnail" alt="getThumbnail" class="img" > </div> </div> </div> </template> <script> export default { data () { return { thumbnail: '', postData: { thumbnail: '', }, } }, computed: { getThumbnail () { return this.$store.getters['change/thumbnail'] }, }, methods: { changeImg (e) { this.thumbnail = e.target.files[0] if (this.thumbnail) { const reader = new FileReader() reader.readAsDataURL(this.thumbnail) reader.onload = () => { this.postData.thumbnail = reader.result + '' } } }, submitImg () { this.$store.dispatch('change/submit', this.thumbnail) }, getImg () { this.$store.dispatch('change/getImg') }, }, } </script> <style lang="scss" scoped> .page { padding: 20px; > .form { background-color: #FFDCDC; > .label { display: block; width: 32px; height: 32px; background-image: url('data:image/svg+xml, <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="%23000" d="M5 8.5c0-.828.672-1.5 1.5-1.5s1.5.672 1.5 1.5c0 .829-.672 1.5-1.5 1.5s-1.5-.671-1.5-1.5zm9 .5l-2.519 4-2.481-1.96-4 5.96h14l-5-8zm8-4v14h-20v-14h20zm2-2h-24v18h24v-18z"/></svg>'); background-repeat: no-repeat; background-size: cover; > .input { display: none; } } > .img { width: 100px; height: 100px; .preview { width: 100px; } } } > .getImg { margin-top: 100px; > .img { width: 100px; height: 100px; > .img { width: 100px; } } } } </style> |
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 |
import firebase from '@/plugins/firebase' export const state = () => ({ thumbnail: '', }) export const getters = { thumbnail: state => { return state.thumbnail }, } export const actions = { submit ({ context }, image) { let storage = firebase.storage() let storageRef = storage.ref().child('file.png') storageRef.put(image) .then(res => console.log(res)) .catch(error => console.log(error)) }, getImg ({ commit }) { let storage = firebase.storage() let storageRef = storage.ref().child('file.png') storageRef.getDownloadURL() .then(res => { console.log(res) commit('getData', res) }) }, } export const mutations = { getData (state, image) { state.thumbnail = image }, } |
まとめ
役割を分けて
切り離すことができました✂︎
前回はonload
をreadAsDataURL
の前に
書いていたため、
役割を分ける際に混乱しました😂
流れをしっかり理解するのは大切ですね。
コードは全てを理屈で理解しようとすると詰む
と言いますが、
理論的に分かるに越したことはないです😂
キャプチャの録画は
GIPHY Captureに
変更してみました💫