avatar

目录
前端文件下载的几种实现方式

通过a标签配合download属性下载文件

html
1
2
<!--  download属性的值是下载后的文件名,href属性的值是 后端文件下载接口地址 -->
<a download="文件名" href="文件下载接口地址"></a>


通过window.open()下载文件

  1. window.open 默认是开启一个新的窗口,一闪然后关闭,这样的用户体验不好
    html
    1
    2
    3
    4
    5
    6
    7
    <button onclick="download()">下载</button>

    <script type="text/javascript">
    function download() {
    window.open('http://localhost:3000/遗留问题.docx')
    }
    </script>
  2. window.open 可以加上第二个参数 window.open(‘/download/1.png’, ‘_self’)。这样就会在当前窗口直接下载了。然而这样是将 url 替换当前页面的url,会触发 beforeunload 等页面事件,如果你的页面监听了该事件做一些操作的话,那就有影响。
  3. 那么还可以使用一个隐藏的 iframe 窗口来达到同样的效果,还可以不触发beforeunload等页面事件。
    html
    1
    2
    3
    4
    5
    6
    7
    8
    <button onclick="handleClick()">立即下载</button>
    <iframe name="myIframe" style="display:none"></iframe>

    <script>
    const handleClick = () => {
    window.open('/download/1.png', 'myIframe');
    }
    </script>


通过form表单下载文件

  1. form表单提交支持get和post两个请求方式 (a标签和window.open()只支持get方式)
    html
    1
    2
    3
    4
    <form action="/download" method="post">
    <p>fileName: <input type="text" name="fileName" /></p>
    <input type="submit" value="Submit" />
    </form>
  2. js动态创建form表单并提交,更灵活
    html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <button onclick="dynamicDownloadFile({ url: '/form', method: 'post', param: { fileName: 'note.txt' } })">form动态提交下载文件</button>

    <script type="text/javascript">
    const dynamicDownloadFile = ({ url, method = 'get', param = {} }) => {
    const form = document.createElement('form');
    form.action = url;
    form.method = method;
    form.target = 'blank';
    Object.keys(param).forEach((item) => {
    const input = document.createElement('input');
    input.type = 'hidden';
    input.name = item;
    input.value = param[item];
    form.appendChild(input);
    });
    document.body.appendChild(form);
    form.submit();
    document.body.removeChild(form);
    }
    </script>
  3. 正常的form表单方式也会触发beforeunload事件,影响体验。可以用iframe的方式绕过
    html
    1
    2
    3
    4
    5
    <form action="/form" method="post" target="innerIframe">
    <p>fileName: <input type="text" name="fileName" /></p>
    <input type="submit" value="Submit" />
    </form>
    <iframe name="innerIframe" style="display:none;"></iframe>


通过数据流形式下载文件

blob

  1. blob对象
    • Binary Large Object,二进制大对象,是一个可以存储二进制文件的容器
    • 早期数据库用blob类型存储声音、图片、二进制文件等
  2. 构建一个Blob对象通常有三种方式
    • 通过Blob对象的构造函数来构建
    • 已有的Blob对象调用slice接口切出一个新的Blob对象
    • canvas API toBlob方法,把当前绘制信息转为一个Blob对象
  3. 服务器端通过二进制文件流的格式返回,前端将数据放进Blob对象中,并利用a标签下载文件属性将文件下载保存到本地
    javascript
    1
    2
    3
    4
    5
    6
    // nodejs 服务器端
    const downloadFile = ctx => {
    const name = ctx.request.query.name;
    ctx.response.body = fs.createReadStream(`server/file/${name}`)
    }
    app.use(route.get('/download', downloadFile)); // 下载文件
    html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <!-- html 客户端 -->
    <button onclick="download('note.txt')">下载</button>

    <script type="text/javascript">
    function download(filename) {
    $.ajax({
    url: `/download?name=${filename}`,
    success(data) {
    const url = window.URL.createObjectURL(new Blob([data.data]))
    const link = document.createElement('a')
    link.style.display = 'none'
    link.href = url
    link.setAttribute('download', filename)
    document.body.appendChild(link)
    link.dispatchEvent(new MouseEvent('click'))
    document.body.removeChild(link)
    }
    })
    }
    </script>


File

  1. File对象
    • File对象继承了Blob并进行了扩展,使其能够支持使用系统上的文件
    • File对象获取png,而File继承自Blob,所以也能转换为BlobURL,但是File还有一个好处就是File对象可以从页面中获取文件(input标签)
  2. 利用File对象下载input中的文件
    html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    文件:<input type="file" id="fileInput">
    <button onclick="downloadFile('icon.png')">下载</button>

    <script type="text/javascript">
    function downloadFile(filename) {
    const fileInput = document.getElementById('fileInput')
    const url = window.URL.createObjectURL(fileInput.files[0])
    const link = document.createElement('a')
    link.style.display = 'none'
    link.href = url
    link.setAttribute('download', filename)
    document.body.appendChild(link)
    link.dispatchEvent(new MouseEvent('click'))
    document.body.removeChild(link)
    }
    </script>

拓展:Ajax和form表单提交区别

  1. ajax:
    • 在提交,请求,接收时,都是异步进行的,网页不需要刷新
    • 在提交时,是在后台新建一个请求
    • 必须使用js来实现,不启用js的浏览器,无法完成操作
    • 在提交,请求,接收时,整个过程都是需要使用程序来对其数据进行处理
  2. from表单:
    • 提交时是新建一个页面,哪怕是提交给自己本身的页面,也是需要刷新的
    • 趋势放弃本页面,再次申请
    • 是浏览器的功能,无论是否开启js,都可以提交表单
    • 提交时,是根据你的表单结构自动完成,不需要代码干预
文章作者: 盛顺炎
文章链接: https://www.shengshunyan.xyz/2020/03/29/%E5%89%8D%E7%AB%AF%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BD%BD%E7%9A%84%E5%87%A0%E7%A7%8D%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 果实的技术分享
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论