Menu

CODE

フロント側のみ通常素材をZIP化しダウンロードさせる

2019/02/09 更新日:2020/05/04
デモページへ

仕様書

基本的にフロント側でPDFやJPGなどをダウンロードさせる方法はaタグにダウンロード属性を付与すれば実装できます。

<a href="URL" download>ダウンロード</a>

今回はPDFやJPGをファイルをまとめて一本化し、ZIPファイルにまとめて、フロント側で処理し、単独ファイル、複数ファイルにかかわらずZIPファイルでダウンロードさせる方法になります。

zip化する上で必要なプラグインを導入していきます。jszip添付ファイルをZipファイルで一括ダウンロードする方法です。プラスしてIEにも対応していきたいのでFileSaver.jsを使用します。

selectタグを使用します。

HTML上ではチェックボックスが存在していますが、これはselectへのチェックの発火になります。実際ダウンロードするソースの選定をするのはselectに集約していきます。

<select multiple="multiple" class="select-image">
  <option data-img-src="download/sample.jpg" value="1">1</option>
  <option data-img-src="download/sample.xlsx" value="2">2</option>
  <option data-img-src="download/sample.docx" value="3">3</option>
  <option data-img-src="download/sample.mp4" value="4">4</option>
  <option data-img-src="download/sample.mp4" value="5">5</option>
  <option data-img-src="download/sample.jpg" value="6">6</option>
  <option data-img-src="download/sample.xlsx" value="7">7</option>
  <option data-img-src="download/sample.docx" value="8">8</option>
  <option data-img-src="download/sample.mp4" value="9">9</option>
  <option data-img-src="download/sample.jpg" value="10">10</option>
  <option data-img-src="download/sample.xlsx" value="11">11</option>
  <option data-img-src="download/sample.docx" value="12">12</option>
</select>

ZIPファイルを生成する

プラグインの設定をしていきajaxでデータを取得していきます。_formatDateによりzipfilenameを決めることもできます。あまり重いファイルだと不可がかかるため軽いファイルを推奨します。

$('.js-trigger').on('click', function() {
    //  複数ファイルをダウンロード
    var progressTemplate =
        '<div class="list-group-item"><div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width: 0%;"></div></div></div>';
    var $dataSelect = $('select.select-image');
    var $downloadBtn = $('.js-trigger');
    var $progress = $('#progress-container');
    var zip;
    var deferreds;
    $(function() {
        // ダウンロードしたい画像が1件以上選択されているとき、ダウンロードボタンをクリック可能にする
        $dataSelect.on('change', _setSelectStatus);
        _setSelectStatus();
        // zipファイル生成&ダウンロード処理
    });
    _createAndDownloadZip();
    /**
     * ダウンロードボタンのクリック制御
     */
    function _setSelectStatus() {
        if ($dataSelect.val() && $dataSelect.val().length > 0) {
            $downloadBtn.removeAttr('disabled');
        } else {
            $downloadBtn.attr('disabled', 'disabled');
        }
    }
    /**
     * ZIPファイルを生成する
     */
    function _createAndDownloadZip() {
        // 初期化
        $progress
            .empty()
            .append(progressTemplate)
            .show();
        zip = new JSZip();
        deferreds = $.Deferred();
        var promise = deferreds;
        console.log($dataSelect);
        // 選択した分ループ
        $.map($dataSelect.val(), function(value, index) {
            var originalUrl = $dataSelect
                .find('option[value="' + value + '"]')
                .data('img-src');
            promise = promise.then(function() {
                var newPromise = new $.Deferred();
                // オリジナル画像を読み込む
                var xhr = new XMLHttpRequest();
                xhr.open('GET', originalUrl, true);
                xhr.responseType = 'arraybuffer';
                xhr.addEventListener('load', function() {
                    // zipにレスポンスデータを追加
                    // zip.file(xhr.response);
                    zip.file(
                        originalUrl.match('.+/(.+?)([?#;].*)?$')[1],
                        xhr.response
                    );
                    newPromise.resolve();
                });
                xhr.send();
                // プログレスバーを更新
                $progress
                    .find('.progress-bar')
                    .width((index + 1) / $dataSelect.val().length * 100 + '%');
                return newPromise;
            });
        });
        // ダウンロードが完了した後でzipファイルを生成してsaveAsメソッドでダウンロード
        promise.then(function() {
            zip.generateAsync({ type: 'blob' }).then(function(content) {
                console.log(content);
                saveAs(
                    content,
                    _formatDate(new Date(), 'YYYYMMDD-hhmmss') + '.zip'
                );
            });
            $progress.hide();
        });
        deferreds.resolve();
    }
    function _formatDate(date, format) {
        if (!format) format = 'YYYY-MM-DD hh:mm:ss.SSS';
        format = format.replace(/YYYY/g, date.getFullYear());
        format = format.replace(/MM/g, ('0' + (date.getMonth() + 1)).slice(-2));
        format = format.replace(/DD/g, ('0' + date.getDate()).slice(-2));
        format = format.replace(/hh/g, ('0' + date.getHours()).slice(-2));
        format = format.replace(/mm/g, ('0' + date.getMinutes()).slice(-2));
        format = format.replace(/ss/g, ('0' + date.getSeconds()).slice(-2));
        if (format.match(/S/g)) {
            var milliSeconds = ('00' + date.getMilliseconds()).slice(-3);
            var length = format.match(/S/g).length;
            for (var i = 0; i < length; i++)
                format = format.replace(/S/, milliSeconds.substring(i, i + 1));
        }
        return format;
    }
});