通过一个动作下载多个文件
我不确定这是否可以使用标准的networking技术。
我希望用户能够一次下载多个文件。 这是文件旁边的单击checkbox,然后获取所有已检查的文件。
是否有可能 – 如果是的话,你推荐什么样的基本策略。 我知道我可以使用彗星技术来创build触发HttpResponse的服务器端事件,但我希望有一个更简单的方法。
HTTP一次不支持多个文件下载。
有两个解决scheme:
- 打开x个窗口来启动文件下载(这将通过JavaScript完成)
- 首选解决scheme创build一个脚本来压缩文件
var links = [ 'https://s3.amazonaws.com/Minecraft.Download/launcher/Minecraft.exe', 'https://s3.amazonaws.com/Minecraft.Download/launcher/Minecraft.dmg', 'https://s3.amazonaws.com/Minecraft.Download/launcher/Minecraft.jar' ]; function downloadAll(urls) { var link = document.createElement('a'); link.setAttribute('download', null); link.style.display = 'none'; document.body.appendChild(link); for (var i = 0; i < urls.length; i++) { link.setAttribute('href', urls[i]); link.click(); } document.body.removeChild(link); }
<button onclick="downloadAll(window.links)">Test me!</button>
您可以创build一组临时隐藏的iframe,通过GET或POST启动下载内容,等待下载启动并删除iframe:
<!DOCTYPE HTML> <html> <body> <button id="download">Download</button> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script> <script type="text/javascript"> $('#download').click(function() { download('http://nogin.info/cv.doc','http://nogin.info/cv.doc'); }); var download = function() { for(var i=0; i<arguments.length; i++) { var iframe = $('<iframe style="visibility: collapse;"></iframe>'); $('body').append(iframe); var content = iframe[0].contentDocument; var form = '<form action="' + arguments[i] + '" method="GET"></form>'; content.write(form); $('form', content).submit(); setTimeout((function(iframe) { return function() { iframe.remove(); } })(iframe), 2000); } } </script> </body> </html>
该解决scheme适用于各种浏览器,不会触发警告。 而不是创build一个iframe
,这里我们为每个文件创build一个链接。 这可以防止popup警告消息。
为了处理循环部分,我们使用setTimeout
,它是在IE中工作所必需的。
/** * Download a list of files. * @author speedplane */ function download_files(files) { function download_next(i) { if (i >= files.length) { return; } var a = document.createElement('a'); a.href = files[i].download; a.target = '_parent'; // Use a.download if available, it prevents plugins from opening. if ('download' in a) { a.download = files[i].filename; } // Add a to the doc for click to work. (document.body || document.documentElement).appendChild(a); if (a.click) { a.click(); // The click method is supported by most browsers. } else { $(a).click(); // Backup using jquery } // Delete the temporary link. a.parentNode.removeChild(a); // Download the next file with a small timeout. The timeout is necessary // for IE, which will otherwise only download the first file. setTimeout(function() { download_next(i + 1); }, 500); } // Initiate the first download. download_next(0); }
<script> // Here's a live example that downloads three test text files: function do_dl() { download_files([ { download: "http://www.nt.az/reg.txt", filename: "regs.txt" }, { download: "https://www.w3.org/TR/PNG/iso_8859-1.txt", filename: "standards.txt" }, { download: "http://qiime.org/_static/Examples/File_Formats/Example_Mapping_File.txt", filename: "example.txt" }, ]); }; </script> <button onclick="do_dl();">Test downloading 3 text files.</button>
最简单的方法是将多个文件捆绑到一个ZIP文件中。
我想你可以使用一堆iframe或popups启动多个文件下载,但是从可用性的angular度来看,ZIP文件还是比较好的。 谁想要点击浏览器将popup的十个“另存为”对话框?
一个jQuery版本的iframe答案:
function download(files) { $.each(files, function(key, value) { $('<iframe></iframe>') .hide() .attr('src', value) .appendTo($('body')) .load(function() { var that = this; setTimeout(function() { $(that).remove(); }, 100); }); }); }
<!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(); }); } }]);
工作示例: https : //plnkr.co/edit/XynXRS7c742JPfCA3IpE?p = preview
我同意一个zip文件是一个整洁的解决scheme…但是,如果你必须推多个文件,这是我想出的解决scheme。 它适用于IE 9及以上(可能更低的版本 – 我没有testing过),Firefox,Safari和Chrome。 Chrome会向用户显示一条消息,以便在您的网站首次使用该文件时,获得他同意下载多个文件的权限。
function deleteIframe (iframe) { iframe.remove(); } function createIFrame (fileURL) { var iframe = $('<iframe style="display:none"></iframe>'); iframe[0].src= fileURL; $('body').append(iframe); timeout(deleteIframe, 60000, iframe); } // This function allows to pass parameters to the function in a timeout that are // frozen and that works in IE9 function timeout(func, time) { var args = []; if (arguments.length >2) { args = Array.prototype.slice.call(arguments, 2); } return setTimeout(function(){ return func.apply(null, args); }, time); } // IE will process only the first one if we put no delay var wait = (isIE ? 1000 : 0); for (var i = 0; i < files.length; i++) { timeout(createIFrame, wait*i, files[i]); }
这种技术的唯一副作用是用户会看到提交和下载对话框之间的延迟。 为了尽量减less这种影响,我build议你使用这里描述的技术和这个问题当浏览器收到文件下载包括设置一个cookie与你的文件知道它已经开始下载时检测。 你将不得不在客户端检查这个cookie,并在服务器端发送它。 不要忘记为你的cookie设置正确的path,否则你可能看不到它。 您也将不得不适应多个文件下载的解决scheme。
为了改善@Dmitry Nogin的回答:这在我的情况下工作。
但是,它没有经过testing,因为我不确定文件对话如何在各种操作系统/浏览器组合上工作。 (因此社区wiki。)
<script> $('#download').click(function () { download(['http://www.arcelormittal.com/ostrava/doc/cv.doc', 'http://www.arcelormittal.com/ostrava/doc/cv.doc']); }); var download = function (ar) { var prevfun=function(){}; ar.forEach(function(address) { var pp=prevfun; var fun=function() { var iframe = $('<iframe style="visibility: collapse;"></iframe>'); $('body').append(iframe); var content = iframe[0].contentDocument; var form = '<form action="' + address + '" method="POST"></form>'; content.write(form); $(form).submit(); setTimeout(function() { $(document).one('mousemove', function() { //<--slightly hacky! iframe.remove(); pp(); }); },2000); } prevfun=fun; }); prevfun(); } </script>
<p class="style1"> <a onclick="downloadAll(window.links)">Balance Sheet Year 2014-2015</a> </p> <script> var links = [ 'pdfs/IMG.pdf', 'pdfs/IMG_0001.pdf', 'pdfs/IMG_0002.pdf', 'pdfs/IMG_0003.pdf', 'pdfs/IMG_0004.pdf', 'pdfs/IMG_0005.pdf', 'pdfs/IMG_0006.pdf' ]; function downloadAll(urls) { var link = document.createElement('a'); link.setAttribute('download','Balance Sheet Year 2014-2015'); link.style.display = 'none'; document.body.appendChild(link); for (var i = 0; i < urls.length; i++) { link.setAttribute('href', urls[i]); link.click(); } document.body.removeChild(link); } </script>
我正在寻找一个解决scheme来做到这一点,但解压JavaScript文件并不像我喜欢的那样干净。 我决定将这些文件封装到一个SVG文件中。
如果你有文件存储在服务器上(我没有),你可以简单地在SVG中设置href。
在我的情况下,我将文件转换为base64并将其embedded到SVG中。
编辑:SVG工作得很好。 如果你只是要下载文件,ZIP可能会更好。 如果你要显示这些文件,那么SVG看起来比较好。
使用Ajax组件时,可以启动多个下载。 因此你必须使用https://cwiki.apache.org/confluence/display/WICKET/AJAX+update+and+file+download+in+one+blow
添加一个AJAXDownload的实例到您的页面或其他。 创build一个AjaxButton并覆盖onSubmit。 创build一个AbstractAjaxTimerBehavior并开始下载。
button = new AjaxButton("button2") { private static final long serialVersionUID = 1L; @Override protected void onSubmit(AjaxRequestTarget target, Form<?> form) { MultiSitePage.this.info(this); target.add(form); form.add(new AbstractAjaxTimerBehavior(Duration.milliseconds(1)) { @Override protected void onTimer(AjaxRequestTarget target) { download.initiate(target); } }); }
快乐的下载!
下面的代码100%的工作。
第1步 :在index.html文件中粘贴以下代码
<!DOCTYPE html> <html ng-app="ang"> <head> <title>Angular Test</title> <meta charset="utf-8" /> </head> <body> <div ng-controller="myController"> <button ng-click="files()">Download All</button> </div> <script src="angular.min.js"></script> <script src="index.js"></script> </body> </html>
第2步 :在index.js文件中粘贴以下代码
"use strict"; var x = angular.module('ang', []); x.controller('myController', function ($scope, $http) { var arr = [ {file:"http://localhost/angularProject/w3logo.jpg", fileName: "imageone"}, {file:"http://localhost/angularProject/cv.doc", fileName: "imagetwo"}, {file:"http://localhost/angularProject/91.png", fileName: "imagethree"} ]; $scope.files = function() { angular.forEach(arr, function(val, key) { $http.get(val.file) .then(function onSuccess(response) { console.log('res', response); var link = document.createElement('a'); link.setAttribute('download', val.fileName); link.setAttribute('href', val.file); link.style.display = 'none'; document.body.appendChild(link); link.click(); document.body.removeChild(link); }) .catch(function onError(error) { console.log('error', error); }) }) }; });
注意 :确保所有要下载的三个文件将与angularProject / index.html或angularProject / index.js文件一起放置在同一个文件夹中。