HTML5+原生JS实现服务器端目录树中多文件下载

HTML5+原生JS实现服务器端目录树中多文件下载

作者:云荒杯倾
作者博客

需求

需求是这样的,服务器上有一个目录,目录下面可能既有文件又有其他目录,其他目录下面也一样,既可能有文件也有目录;浏览器要显示有这个目录,并提供这个目录下所有文件的一键下载功能。

实现原理

实现这个需求,本程序考虑到的知识点有html5 <a>标签的下载功能、数据结构中树的广度优先遍历算法、一点http知识和一点JS局限性的知识。

HTML5 <a>标签的下载功能

首先说HTML5 <a>标签的下载功能
HTML5的<a>标签有一个download属性,如果你设置了这个属性,那么点击这个链接,就不再是跳转到这个<a>标签href引用的地址了,而是直接去下载href所代表的一个文件。

<a herf="./bbb.html">这是超链接</a>

这样,点击这是超链接几个字,只能页面跳转到bbb.html。
而,

<a herf="./bbb.html" download="ccc.html">这是超链接</a>

这样,加了download属性后,你再点击这是超链接几个字,就直接下载bbb.html到你的本地机器(客户端)了,且文件会改名为“ccc.html”。如果只写download,则是保持原始文件名下载。

一点http知识

http是不提供目录遍历的,所以暂时不知道其他实现方法是否碰到了这个点,所以导致程序失败。某种程度上,本文的程序算是避开了这个点?

一点JS局限性的知识

JS语言跑在浏览器的话,是不能操作本地(客户端)太多东西的,其中就包括一些文件操作,而文件夹创建操作就包括在这些限制操作之内。这也是无法实现将服务器上的一个目录按照其目录结构原样拷贝到本地(客户端)的原因。

看过一篇博文的举例很好,他说,如果我有一个网站,你是访客,你访问,点击了某个链接,我就把网站的一个目录树(假设有一百万个txt),拷贝到你的本地,你会不会恼火?而且,之所以浏览器不提供这些功能,主要是出于客户端安全方面的考虑。

做这个需求的时候,看到IE上有一个activexObject对象,可以在本地创建文件夹。但是想想就只有IE支持,还是算了。

综上,本程序是将服务器上一个有层次的目录树里面所有的文件,通过浏览器下载到本地同一个文件夹下的。

不过因为下载一个目录树的功能,最主要的考察点还是树状数据结构的遍历,如果哪天浏览器都实现了本地创建文件夹,本程序的代码仍有参考价值。

目录树的广度优先遍历及本程序的实现思路

本例的思路是,前后端定义一个目录树的接口。

前端通过xhr拿到数据。

一层一层遍历这颗目录树,直到遍历完这个目录树下所有文件,也就能拿到这所有文件的URL了。假设一共有n个文件,也就是n个URL。

拿到n个URL后,注册这个目录对应的下载该目录下所有文件按钮的监听器,监听器内创建n个html5 <a>标签,<a>标签的href分别赋值url路径,所有<a>标签设置download属性。

如此,就实现了加载HTML,HTML上有一个代表着服务器上一个目录的目录名,目录名后面有一个下载该目录下所有文件的按钮,点击该按钮,就从服务器下载了该目录下所有文件到本地。

本文定义的目录树结构

目录树接口定义如下,一个目录要有name(也就是URL),file是该层目录下裸露的文件,childDir是该层有的下一层的目录,如此往复。。。如果到了某一目录,既没有文件有没有目录,那么name就定义为[]数组,childDir也定义为[]数组。

本例中的目录树是:根目录./chrome61module,其下有三个文件,分别是aa.css,aa.js,module-test.html,还有一个目录bb;bb目录下只有两个文件bb.js和bb.html。

//假设这是从服务器取来的a链接的目录结构
        var rootDir = {
            "name":"./chrome61module",
            "file":["/aa.css","/aa.js","/module-test.html"],
            "childDir":[{
                "name":"./chrome61module/bb",
                "file":["/bb.js","/bb.html"],
                "childDir":[]
            },{}]
        };

效果展示


图1 HTML页面


图2 点击下载该目录下所有文件Chrome会提示你是否要下载多个文件


图3 本例中下载成功的五个文件

代码展示

代码比较简单,就直接放了,大家直接自己粘贴了,就能运行,注意修改目录树结构为你自己的

<body>
    <a href="./chrome61module" id="aDir">chrome61module目录</a>
    <button id="downloadDir">下载目录下所有文件</button>
    <script>
        //假设这是从服务器取来的a链接的目录结构
        var rootDir = {
            "name":"./chrome61module",
            "file":["/aa.css","/aa.js","/module-test.html"],
            "childDir":[{
                "name":"./chrome61module/bb",
                "file":["/bb.js","/bb.html"],
                "childDir":[]
            },{}]
        };

        //DOM
        var btnDownload = document.getElementById("downloadDir");
        var aDir = document.getElementById("aDir");
        //按钮监听器
        btnDownload.addEventListener("click",downloadDir);
        function downloadDir() {
            //处理某一层
            function oneTreeLayerProcess(dir) {
                if(JSON.stringify(dir) !== "{}"){
                    if(dir.file.length !== 0){
                        for(let i = 0; i< dir.file.length; i++){
                            var j = document.createElement("a");
                            j.href = dir.name + dir.file[i];
                            j.download = dir.file[i].slice(1);
                            j.click();
                        }
                    }
                    if(dir.childDir.length !== 0){
                        for(let i =0; i < dir.childDir.length; i++){
                            //递归
                            oneTreeLayerProcess(dir.childDir[i]);
                        }
                    }
                }
            }
            oneTreeLayerProcess(rootDir);
        }

    </script>
</body>

总结

1、由于http和JS能力的限制,目前仅能实现文件下载,不能实现文件夹下载或者文件夹本地创建,因此想原样拷贝服务器上一个目录到本地机器,使用JS目前较难做到。

2、由于本例实现的将一个目录树下所有文件都平行下载到本地的同一个文件夹下。造成客户端即使下载了也无法理解服务器上原目录树的困难。
一点改进是,如果使用download=“”,将“”内的文件名改为包含路径的文件名,也许下载以后,客户端可以获悉其原来在服务器上的对应的目录层级,从而可以自己后续处理。

3、如果可能,还是按照压缩包的形式下载一个目录也许更好。

原文地址:https://www.cnblogs.com/homehtml/p/12208273.html

时间: 2024-10-16 11:35:37

HTML5+原生JS实现服务器端目录树中多文件下载的相关文章

原生JS返回服务器端时间

最近的项目需要做一个倒计时的功能,找了好多资料,都写的很清楚,也看得懂是什么意思,但都是只输出时间,而我是要返回一个时间,所以我修修改改成了这个方法,还不错,兼容IE6.0,嘎嘎嘎. 上代码: 1 /// <summary> 2 /// 返回服务器端时间 3 /// </summary> 4 var getServeTime = function () { 5 //创建XMLHttpRequest对象 6 var http = window.XMLHttpRequest ? new

PhoneGap或者Cordova框架下实现Html5中JS调用Android原生代码

PhoneGap或者Cordova框架下实现Html5中JS调用Android原生代码 看看新闻网>看引擎>开源产品 0人收藏此文章, 发表于8小时前(2013-09-06 00:39) , 已有13次阅读 ,共0个评论 依照我一惯得套路,我会先说一点废话. PhoneGap和Cordova什么关系?为什么有的地方叫Cordova而有的地方叫PhoneGap ?PhoneGap是一款HTML5平台.通过它,开发商能够使用HTML.CSS及JavaScript来开发本地移动应用程序.因此,眼下开

蓝鸥原生JS:js的引入方式及js的基本数据类型

蓝鸥原生JS:js的引入方式及js的基本数据类型 蓝鸥零基础学习HTML5-html+css基础 http://11824614.blog.51cto.com/11814614/1852769 js的引入方式 在一对 script 标签中引入js代码 通过这种方式引入,可以把js代码和html代码写在同一个文件中,但是注意:最好把js代码写在body之后,文档的加载顺序是从上到下加载的,先把页面内容渲染出来,再加入用户交互,这样用户体验会大大加强. 示例代码: <html lang="en

跨域问题相关知识详解(原生js和jquery两种方法实现jsonp跨域)

1.同源策略 同源策略(Same origin policy),它是由Netscape提出的一个著名的安全策略.同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响.可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现,现在所有支持JavaScript 的浏览器都会使用这个策略. 所谓同源,就是指两个页面具有相同的协议,主机(也常说域名),端口,三个要素缺一不可. 所谓同源策略,指的是浏览器对不同源的脚本或者文本的访问

Agile国人出品HTML5+CSS3+JS移动应用开发框架

Agile 是一个基于HTML5+CSS3+JS的移动应用开发框架,在体验上尽量接近Native Like,并且同时支持单页模式和多页模式. Agile 让HTML5在移动应用开发中充分发挥优势.所有开发者都能快速上手.所有设备都可以适配.所有项目都适用. 简单.可扩展 Agile 支持Zepto和jQuery双引擎及相应的扩展:同时Agile均支持单页模式和多页模式的移动应用,可以与ExMobi.PhoneGap等流行的跨平台开发框架一起使用. 一个框架.多种设备 你的移动应用能在 Agile

原生js封装ajax:传json,str,excel文件上传表单提交

由于项目中需要在提交ajax前设置header信息,jquery的ajax实现不了,我们自己封装几个常用的ajax方法. jQuery的ajax普通封装 var ajaxFn = function(uri, data, cb) { $.ajax({ url: uri, type: 'POST', dataType: 'json', data: data, }) .done(cb) .fail(function() { console.log("error"); }) .always(f

放弃jQuery,使用原生js吧!

转自:http://itakeo.com/blog/2015/07/28/nojq/ 随着IE6.7.8的逐渐淘汰,HTML5的兴起,以及侧重点放在了移动端,jQuery可能变的不在那么重要,原生一样很好用.下面介绍几个原生替换jq的方法. 获取元素 JQuery $('.xxx'); //class获取 $('#xxx'); //id获取 $('.xxx.ccc'); //同时包含xxx和ccc $('.xxx,.zzz'); //多选 $('.xxx div'); //子类 $('.xxx

AJAX请求和跨域请求详解(原生JS、Jquery)

一.概述 AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术. AJAX = 异步 JavaScript 和 XML,是一种用于创建快速动态网页的技术.通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新.这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新.传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面. 本博客实验环境: python:2.7.11 web框架:tonado jquery:2.1.1 二.“伪”AJAX 由于

原生JS封装Ajax插件(同域&amp;&amp;jsonp跨域)

抛出一个问题,其实所谓的熟悉原生JS,怎样的程度才是熟悉呢? 最近都在做原生JS熟悉的练习... 用原生Js封装了一个Ajax插件,引入一般的项目,传传数据,感觉还是可行的...简单说说思路,如有不正确的地方,还望指正^_^ 一.Ajax核心,创建XHR对象 Ajax技术的核心是XMLHttpRequest对象(简称XHR),IE5是第一款引入XHR对象的浏览器,而IE5中的XHR对象是通过MSXML库中的一个ActiveX对象实现的,因此在IE中可能有3个版本,即MSXML2.XMLHttp.