2019-10-31に投稿

Vue + Buefyでサーバーからファイルを受け取ってファイルアップロードにセットする

そんな需要がどこにあるのか知らんが。

動作環境

OS: macOS High Sierra 10.13.6
ブラウザ: Chrome 77.0.3865.90
vue: 2.6.10
buefy: 0.8.4

はじめに

やりたいこととしては、タイトルの通りです。

需要があるとは到底思えないのだけれど、思いついてやってみたらそれっぽくできてしまったので。

無理やり使う場面を考えるとすると、例えば電子申請伝票に添付ファイルを(領収証とかをpdfで)つけたいのだけど、申請前に一時保存する機能をつけたい。保存時に添付ファイルはサーバーに送られるのだけど、再編集時にファイルアップロードにセットしたい、とか。でもそんな業務チックなシステムをvue + buefyでやるとは思えないので、やっぱり使う場面が思い浮かばない。

普通のファイルアップロードだと無理

普通のファイルアップロード(input type="file")だとセキュリティ上の理由で無理。まあ、そうだよなって感じではありますが。
別に、valueに端末のパスを指定して悪さしたいわけじゃなくて、直にfiles[0]にFileオブジェクトを突っ込んでおきたいのだけど。。。

Buefyならなんとか

Buefyのb-uploadなら、VueのdataにFileオブジェクトを保持して、擬似的(?)にファイルアップロードを作っているっぽいのでできそうです。
やる場面があるか知らんが。

要は、VueのdataにFileオブジェクトを突っ込めれば良いので、サーバーからのファイルのデータをFileオブジェクトに変換するというのがメインの作業になります。

面倒なので前回のソースに手を加える感じにします。

と、その前にサーバー側。
よしなにやれば良いと思いますが、今回は簡単にLaravel使ってこんな感じでStorageでgetして返してます。

return Storage::get('PUBLN-S-logo.png');

でフロント側

<template>
    <div>
        <b-field class="file">
            <b-upload v-model="file">
                <a class="button is-primary">
                    <b-icon icon="upload"></b-icon>
                    <span>Click to upload</span>
                </a>
            </b-upload>
            <span class="file-name" v-if="file">
                {{ file.name }}
            </span>
        </b-field>
        <!-- サーバーから取得するボタンを追加 -->
        <b-button type="is-info" @click="getFile">サーバーから取得</b-button>
        <img :src="image" />
    </div>
</template>

<script>
export default {
    data:function(){
        return {
            file:null
        }
    },
    computed:{
        image:function(){
            return this.file ? window.URL.createObjectURL(this.file) : ""
        }
    },
    // サーバーからファイルを取得するメソッドを追加
    methods:{
        getFile:async function(){
            const response = await fetch('/api/getFile')
            if(response.ok){
                const blob = await response.blob()
                this.file = new File([blob],'PUBLN-S-logo.png')
            }
        }
    }
}
</script>

fetchだとレスポンスをblobをブジェクトに変換するblobメソッドがあるので、それを使います。
blobだとb-uploadが受け付けないのでFileオブジェクトにする必要がありますが、コンストラクタでblobを渡すことができるので、難しくありません。配列で渡す必要があるのをうっかりしそうですが。

ボタン押す前.png
ボタンを押すと
ボタン押した後.png
サーバーから取ってきてセット(ついでにプレビュー)

終わりに

細かいところは検証してないですが、とりあえず動いたので。
たぶん、色々セキュリティとかも含めちゃんとしなきゃいけないとは思います。
そもそも使いどころはわかりませんが。


hammhiko

恥を晒して生きていきます。

Crieitは個人で開発中です。 興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!

ボードとは?

関連記事

コメント