前言

在我们日常开发中,经常会遇到上传文件的问题,不同于别的表单提交等信息传输那样简单,文件上传是一个很复杂的功能,需要考虑很多的问题,比如拖拽上传,上传预览,上传不同文件类型,限制上传大小,多文件上传,大文件上传,断点续传,还要考虑各种兼容性等等。因此,我们急需一个好用的上传插件,而jQuery-file-upload就是其中最好用评分最高的一款上传插件,在Github上的start数量超过了2万8千多。今天我们就一起来学习一下它的用法。

jQuery-file-upload简介

jQuery-file-upload是一个文件上传组件,具有多文件上传选择,拖拽支持,进度条,验证并预览图片,支持音视频的jQuery插件。它还支持跨域上传,分片上传,断点续传,图片缩放等功能。它可以和任意的后台相配合(PHP, Python, Ruby on Rails, Java, Node.js, Go 等等)。

它的具体特性有如下这些:

  • 多文件上传

支持一次性选择多个文件并同时上传

  • 拖拽上传

支持从桌面或者文件管理器中拖拽文件至浏览器中上传

  • 上传进度条

可以为每个独立的文件和所有的上传显示上传进度条

  • 随时取消上传

可以随时取消每个独立的上传文件

  • 随时恢复上传

取消上传的文件可以随时恢复上传,如果浏览器支持Blob这个API的话。

  • 分片上传

大文件可以被切分成小的块分片上传,如果浏览器支持Blob这个API的话。

  • 图片缩放

图片可以自动进行缩放,如果浏览器支持一些必须的JS API的话。

  • 图片,音频,视频预览

可以本地预览图片,音频,视频等,如果浏览器支持一些必须的JS API的话。

  • 不需要Flash等浏览器插件:

JQuery-file-upload的实现是基于标准的HTML5,不需要额外的浏览器插件。

  • 兼容旧浏览器

如果浏览器支持XMLHttpRequests的话,则使用XMLHttpRequests进行上传,否则使用iframes作为回调对于旧的浏览器。

  • 支持元素表单文件上传

通过使用标准的HTML表单作为组件元素支持渐进增强功能。

  • 跨域文件上传

通过使用跨域的XMLHttpRequests或者iframe跳转来支持跨域文件上传。

  • 多个插件实例

允许在同一个页面使用多个插件实例。

  • 可自定义化可拓展化
    提供了一个接口去设置独立的配置和定义回调函数对于多个上传事件。
  • 支持Multipart格式和文件流格式上传

文件可以被使用标准的multipart/form-data格式上传或者文件流的格式上传(HTTP PUT file upload).

  • 兼容任意类型后台

可以很好的和任意类型语言平台进行合作(PHP, Python, Ruby on Rails, Java, Node.js, Go 等等)。

在线DEMO地址

这是官方的在线测试jQuery-file-upload的地址:https://blueimp.github.io/jQuery-File-Upload/

安装

在自己服务器上安装插件

虽然官方的DEMO实现包含了一些远程的文件,但是在你自己主机上使用的时候推荐把它们都下载下来。这些除了托管在谷歌的内容分发网络上的脚本,比github的demo页面更加地可靠。

  • 在PHP网站上使用插件

去存档页面下载https://github.com/blueimp/jQuery-File-Upload/releasesjQuery-file-upload插件,解压后,将server/php里面的文件上传到你自己的服务器即可。

  • 在谷歌应用引擎上安装插件

去存档页面下载https://github.com/blueimp/jQuery-File-Upload/releasesjQuery-file-upload插件,然后上传server/gae-python或者server/gae-go目录到你的应用引擎实例,编辑app.yaml文件,将jquery-file-upload修改为你的APP ID,然后将刚才解压的目录,除了server以外的整个目录上传到任意的主机,将main.js中的url改为你的地址即可。

  • 在Nodejs中使用插件

通过NPM进行安装:

npm install blueimp-file-upload-node

启动服务:

./node_modules/blueimp-file-upload-node/server.js

main.js中的url改为你的服务器地址即可。

  • 在自定义化服务器中使用

在这里有其他的一些具体的其他语言服务器的配置教程https://github.com/blueimp/jQuery-File-Upload/wiki,修改你的main.js中的url或者你可以去掉配置项中的url配置,然后在index.html中修改表单的action的地址即可。服务端返回的JSON数据应该类似下面这样:

{"files": [
  {
    "name": "picture1.jpg",
    "size": 902604,
    "url": "http:\/\/example.org\/files\/picture1.jpg",
    "thumbnailUrl": "http:\/\/example.org\/files\/thumbnail\/picture1.jpg",
    "deleteUrl": "http:\/\/example.org\/files\/picture1.jpg",
    "deleteType": "DELETE"
  },
  {
    "name": "picture2.jpg",
    "size": 841946,
    "url": "http:\/\/example.org\/files\/picture2.jpg",
    "thumbnailUrl": "http:\/\/example.org\/files\/thumbnail\/picture2.jpg",
    "deleteUrl": "http:\/\/example.org\/files\/picture2.jpg",
    "deleteType": "DELETE"
  }
]}

如果是返回错误信息,应该类似下面这样:

{"files": [
  {
    "name": "picture1.jpg",
    "size": 902604,
    "error": "Filetype not allowed"
  },
  {
    "name": "picture2.jpg",
    "size": 841946,
    "error": "Filetype not allowed"
  }
]}

如果删除了文件的话,返回值应该类似这样:

{"files": [
  {
    "picture1.jpg": true
  },
  {
    "picture2.jpg": true
  }
]}

注意:即使只有一个文件也应该返回files数组的形式。

Content-Type商议

文件上传插件利用iframe传输模块,用于IE和Opera等尚未支持XMLHTTPRequest文件上传的浏览器。
如果iframe响应设置为application/json,则基于iframe的上传需要JSON响应的content-typetext/plaintext/html - 它们将显示不希望的下载对话框。

您可以使用Accept标头为文件上传响应提供不同的内容类型。 以下是Accept content-type变体的(PHP)示例代码片段:

<?php
header('Vary: Accept');
if (isset($_SERVER['HTTP_ACCEPT']) &&
    (strpos($_SERVER['HTTP_ACCEPT'], 'application/json') !== false)) {
    header('Content-type: application/json');
} else {
    header('Content-type: text/plain');
}
?>

下面是Ruby on Rails的代码示例:

def update_attachment
  name  = params[:attachment_name]
  style = params[:attachment_style]
  image = params[:user][name]

  raise "No attachment #{name} for User!" unless User.attachment_definitions[name.to_sym]

  current_user.update("#{name}" => image)
  render(json: current_user.to_fileupload(name, style), content_type: request.format)
end

最小化安装

下载的包的示例都是使用bootstrap完整的用户界面,如果我们需要自定义前端界面,就需要最小化安装。

一个最小化的基本的html页面如下:

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>jQuery File Upload Example</title>
</head>
<body>
<input id="fileupload" type="file" name="files[]" data-url="server/php/" multiple>
<script src="js/vendor/jquery.min.js"></script>
<script src="js/vendor/jquery.ui.widget.js"></script>
<script src="js/jquery.iframe-transport.js"></script>
<script src="js/jquery.fileupload.js"></script>
<script>
$(function () {
    $('#fileupload').fileupload({
        dataType: 'json',
        done: function (e, data) {
            $.each(data.result.files, function (index, file) {
                $('<p/>').text(file.name).appendTo(document.body);
            });
        }
    });
});
</script>
</body> 
</html>

如果你想要展示进度条的话,可以在配置项中添加:

$('#fileupload').fileupload({
    /* ... */
    progressall: function (e, data) {
        var progress = parseInt(data.loaded / data.total * 100, 10);
        $('#progress .bar').css(
            'width',
            progress + '%'
        );
    }
});

然后在页面上加入进度条元素:

<div id="progress">
    <div class="bar" style="width: 0%;"></div>
</div>

如果你想要在上传的周期时间内将一个文件绑定在一个元素节点上,你可以使用context选项(实际上它是jqery.ajax的一个选项):

$(function () {
    $('#fileupload').fileupload({
        dataType: 'json',
        add: function (e, data) {
            data.context = $('<p/>').text('Uploading...').appendTo(document.body);
            data.submit();
        },
        done: function (e, data) {
            data.context.text('Upload finished.');
        }
    });
});

如果你想要点击一个按钮然后开始上传的话,也很容易:

$(function () {
    $('#fileupload').fileupload({
        dataType: 'json',
        add: function (e, data) {
            data.context = $('<button/>').text('Upload')
                .appendTo(document.body)
                .click(function () {
                    data.context = $('<p/>').text('Uploading...').replaceAll($(this));
                    data.submit();
                });
        },
        done: function (e, data) {
            data.context.text('Upload finished.');
        }
    });
});

启用本地图片缩放

首先需要添加下面的所有脚本文件:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<script src="js/vendor/jquery.ui.widget.js"></script>
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
<script src="https://blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
<!-- The Canvas to Blob plugin is included for image resizing functionality -->
<script src="https://blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
<script src="js/jquery.iframe-transport.js"></script>
<!-- The basic File Upload plugin -->
<script src="js/jquery.fileupload.js"></script>
<!-- The File Upload processing plugin -->
<script src="js/jquery.fileupload-process.js"></script>
<!-- The File Upload image preview & resize plugin -->
<script src="js/jquery.fileupload-image.js"></script>

然后设置选项disableImageResizefalse,或者你也可以自定义:

$('#fileupload').fileupload({
    url: '//jquery-file-upload.appspot.com/',
    dataType: 'json',
    // Enable image resizing, except for Android and Opera,
    // which actually support image resizing, but fail to
    // send Blob objects via XHR requests:
    disableImageResize: /Android(?!.*Chrome)|Opera/
        .test(window.navigator && navigator.userAgent),
    imageMaxWidth: 800,
    imageMaxHeight: 800,
    imageCrop: true // 裁切图片
})

依赖

跨域文件上传使用了 Iframe Transport plugin,需要一个一个跳转去服务器去取回上传结果。我们的 例子使用了 result.html作为一个服务器的静态的跳转页面 。
JQuery-file-upload的官方仓库还包括了 jQuery XDomainRequest Transport plugin, 它可以限制跨域AJAX请求在IE8和IE9中。XDomainRequest对象只允许GETPOST请求,不允许文件上传。在Demo中被使用来跨域删除文件服务。

浏览器支持

  • 桌面浏览器

    • Google Chrome
    • Apple Safari 4.0+
    • Mozilla Firefox 3.0+
    • Opera 11.0+
    • Microsoft Internet Explorer 6.0+
  • 手机浏览器

    • Apple Safari on iOS 6.0+
    • Google Chrome on iOS 6.0+
    • Google Chrome on Android 4.0+
    • Default Browser on Android 2.3+
    • Opera Mobile 12.0+

更多浏览器支持细节可以参考这个页面Extended browser support information

参考

更多精彩内容请看下一章:
jQuery-file-upload使用方法详解(二)