リアクティブでSPAでなければ、サーバサイドにPOSTしてファイルをダウンロードさせれば簡単だけど
v-router とか使うと簡単には行かず、困ったのだけれど、
以下の方法で受け渡しできたので備忘録として記載しておく。
【仕様】
・ダウンロードボタンを押すと、サーバ側で作成されたファイルをダウンロードする。
【前提】
・vue から直接サーバ側へはPOSTできない。(ルーターが邪魔する。)
・ストア+API経由でサーバ側とのデータのやり取りはできる。
【サーバ側実装】
今回は、API経由でデータが渡されると、サーバ側でファイルを作成し、base64エンコードした内容を
json形式で { DATA: xxxx } として返すようにした。
【クライアント側実装】
こんな感じ
今回の肝は以下の2箇所。
・base64 をデコードする部分
・blobファイルをダウンロードさせる部分。
methods: {
/**
* ダウンロード
*/
async download() {
let info = { // api に渡す引数があれば、こんな感じで受け渡す。
name: "download.csv"
};
let data = await this.$store.dispatch("download", { info });
// base64をデコードする。
let base64 = data["DATA"];
let bin = atob(base64.replace(/^.*,/, ''));
let buffer = new Uint8Array(bin.length);
for (var i = 0; i < bin.length; i++) {
buffer[i] = bin.charCodeAt(i);
}
// 以下のコードが実行されると、勝手にファイルがダウンロードされる。
const blob = new Blob([buffer.buffer], { type: 'application/csv'});
let link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = 'download.csv';
link.click();
}
},
download() を呼び出すボタンはこんな感じ。
<v-btn text @click="download" v-bind="attrs" v-on="on">
<v-icon>mdi-download</v-icon>
</v-btn>
直接、サーバサイドにPOSTできれば簡単だったけれど、そうすると他とセオリーが異なってしまう。
ボタンが押されると、すぐ遷移してそちらで処理されるのとは異なり、
ボタンが押されると非同期で axios 通信が行われ、データを受け取った後にダウンロードされることになる。