How can I let a user download multiple files when

2020-01-27 05:06发布

So I have a httpd server running which has links to a bunch of files. Lets say the user selects three files from a file list to download and they're located at:

mysite.com/file1 
mysite.com/file2
mysite.com/file3

When they click the download button I want them to download these three files from the links above.

My download button looks something like:

var downloadButton = new Ext.Button({
  text: "Download",
  handler: function(){
    //download the three files here
  }
});

8条回答
地球回转人心会变
2楼-- · 2020-01-27 05:49

This works in all browsers (IE11, Firefox, Microsoft Edge, Chrome and Chrome Mobile) My documents are in multiple select elements. The browsers seem to have issues when you try to do it too fast... So I used a timeout.

<select class="document">
    <option val="word.docx">some word document</option>
</select>

//user clicks a download button to download all selected documents
    $('#downloadDocumentsButton').click(function () {
        var interval = 1000;
        //select elements have class name of "document"
        $('.document').each(function (index, element) {
            var doc = $(element).val();
            if (doc) {
                setTimeout(function () {
                    window.location = doc;
                }, interval * (index + 1));
            }
        });
    });

This solution uses promises:

function downloadDocs(docs) {
    docs[0].then(function (result) {
        if (result.web) {
            window.open(result.doc);
        }
        else {
            window.location = result.doc;
        }
        if (docs.length > 1) {
            setTimeout(function () { return downloadDocs(docs.slice(1)); }, 2000);
        }
    });
}

 $('#downloadDocumentsButton').click(function () {
    var files = [];
    $('.document').each(function (index, element) {
        var doc = $(element).val();
        var ext = doc.split('.')[doc.split('.').length - 1];

        if (doc && $.inArray(ext, docTypes) > -1) {
            files.unshift(Promise.resolve({ doc: doc, web: false }));
        }
        else if (doc && ($.inArray(ext, webTypes) > -1 || ext.includes('?'))) {
            files.push(Promise.resolve({ doc: doc, web: true }));
        }
    });

    downloadDocs(files);
});
查看更多
趁早两清
3楼-- · 2020-01-27 05:50

I fond that executing click() event on a element inside a for loop for multiple files download works only for limited number of files (10 files in my case). The only reason that would explain this behavior that made sense to me, was speed/intervals of downloads executed by click() events.

I figure out that, if I slow down execution of click() event, then I will be able to downloads all files.

This is solution that worked for me.

var urls = [
  'http://example.com/file1',
  'http://example.com/file2',
  'http://example.com/file3'
]

var interval = setInterval(download, 300, urls);

function download(urls) {
  var url = urls.pop();

  var a = document.createElement("a");
  a.setAttribute('href', url);
  a.setAttribute('download', '');
  a.setAttribute('target', '_blank');
  a.click();

  if (urls.length == 0) {
    clearInterval(interval);
  }
}

I execute download event click() every 300ms. When there is no more files to download urls.length == 0 then, I execute clearInterval on interval function to stop downloads.

查看更多
家丑人穷心不美
4楼-- · 2020-01-27 05:50
    <!DOCTYPE html>
    <html ng-app='app'>
        <head>
            <title>
            </title>
            <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
            <link rel="stylesheet" href="style.css">
        </head>
        <body ng-cloack>        
            <div class="container" ng-controller='FirstCtrl'>           
              <table class="table table-bordered table-downloads">
                <thead>
                  <tr>
                    <th>Select</th>
                    <th>File name</th>
                    <th>Downloads</th>
                  </tr>
                </thead>
                <tbody>
                  <tr ng-repeat = 'tableData in tableDatas'>
                    <td>
                        <div class="checkbox">
                          <input type="checkbox" name="{{tableData.name}}" id="{{tableData.name}}" value="{{tableData.name}}" ng-model= 'tableData.checked' ng-change="selected()">
                        </div>
                    </td>
                    <td>{{tableData.fileName}}</td>
                    <td>
                        <a target="_self" id="download-{{tableData.name}}" ng-href="{{tableData.filePath}}" class="btn btn-success pull-right downloadable" download>download</a>
                    </td>
                  </tr>              
                </tbody>
              </table>
                <a class="btn btn-success pull-right" ng-click='downloadAll()'>download selected</a>

                <p>{{selectedone}}</p>
            </div>
            <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
            <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
            <script src="script.js"></script>
        </body>
    </html>


app.js


var app = angular.module('app', []);            
app.controller('FirstCtrl', ['$scope','$http', '$filter', function($scope, $http, $filter){

$scope.tableDatas = [
    {name: 'value1', fileName:'file1', filePath: 'data/file1.txt', selected: true},
    {name: 'value2', fileName:'file2', filePath: 'data/file2.txt', selected: true},
    {name: 'value3', fileName:'file3', filePath: 'data/file3.txt', selected: false},
    {name: 'value4', fileName:'file4', filePath: 'data/file4.txt', selected: true},
    {name: 'value5', fileName:'file5', filePath: 'data/file5.txt', selected: true},
    {name: 'value6', fileName:'file6', filePath: 'data/file6.txt', selected: false},
  ];  
$scope.application = [];   

$scope.selected = function() {
    $scope.application = $filter('filter')($scope.tableDatas, {
      checked: true
    });
}

$scope.downloadAll = function(){
    $scope.selectedone = [];     
    angular.forEach($scope.application,function(val){
       $scope.selectedone.push(val.name);
       $scope.id = val.name;        
       angular.element('#'+val.name).closest('tr').find('.downloadable')[0].click();
    });
}         


}]);

plunker example: https://plnkr.co/edit/XynXRS7c742JPfCA3IpE?p=preview

查看更多
相关推荐>>
5楼-- · 2020-01-27 05:54

The best way to do this is to have your files zipped and link to that:

The other solution can be found here: How to make a link open multiple pages when clicked

Which states the following:

HTML:

<a href="#" class="yourlink">Download</a>

JS:

$('a.yourlink').click(function(e) {
    e.preventDefault();
    window.open('mysite.com/file1');
    window.open('mysite.com/file2');
    window.open('mysite.com/file3');
});

Having said this, I would still go with zipping the file, as this implementation requires JavaScript and can also sometimes be blocked as popups.

查看更多
Evening l夕情丶
6楼-- · 2020-01-27 05:57

You can do it, creating mouse events and dispatching them to button. Sourse.

hrefList=['mysite.com/1.jpg', 'mysite.com/2.mp4', 'mysite.com/3.gif'];
buttonDownloadAll=document.createElement('a');
buttonDownloadAll.innerText='Download all';
buttonDownloadAll.href='';
buttonDownloadAll.download=false;
downloadFunc=function(){
    buttonDownloadAll.setAttribute('onclick', '');
    buttonDownloadAll.download=true;
    for(var i=0; i<hrefList.length-1; i++){
        buttonDownloadAll.href=hrefList[i];
        var clickEvent = document.createEvent('MouseEvent');
		clickEvent.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); 
        buttonDownloadAll.dispatchEvent(clickEvent);
    }
    buttonDownloadAll.setAttribute('onclick', 'downloadFunc()');
    buttonDownloadAll.download=false;
    buttonDownloadAll.href='';
};
buttonDownloadAll.setAttribute('onclick', 'downloadFunc()');
document.body.appendChild(buttonDownloadAll);

查看更多
Anthone
7楼-- · 2020-01-27 05:58

This was the method which worked best for me and didn't open up new tabs, but just downloaded the files/images I required:

var filesForDownload = [];
filesForDownload( { path: "/path/file1.txt", name: "file1.txt" } );
filesForDownload( { path: "/path/file2.jpg", name: "file2.jpg" } );
filesForDownload( { path: "/path/file3.png", name: "file3.png" } );
filesForDownload( { path: "/path/file4.txt", name: "file4.txt" } );

$jq('input.downloadAll').click( function( e )
{
    e.preventDefault();

    var temporaryDownloadLink = document.createElement("a");
    temporaryDownloadLink.style.display = 'none';

    document.body.appendChild( temporaryDownloadLink );

    for( var n = 0; n < filesForDownload.length; n++ )
    {
        var download = filesForDownload[n];
        temporaryDownloadLink.setAttribute( 'href', download.path );
        temporaryDownloadLink.setAttribute( 'download', download.name );

        temporaryDownloadLink.click();
    }

    document.body.removeChild( temporaryDownloadLink );
} );
查看更多
登录 后发表回答