图片上传插件HHuploadify

[2017.8.29] 我对HHuploadify进行了一次升级,用的同学还是有一些,所以感觉有必要进行继续维护。升级的目的有两个,一是脱离jquery,让它可以单独运行,二是适应module化编程的趋势,提供es6的源码导出。升级之后,以前提供的一些抽象化操作函数去掉了,需要开发者自己实现,但是实现起来更加简单。具体请到github上查看源码了解详情。

简介

有一个著名的图片上传插件uploadify,在这个插件基础上,Huploadify被开发出来,是由国人开发的,使用起来也比较好用。但是,我 希望对自己的项目进行定制,希望实现像淘宝添加图片那样,点击一个上传按钮,然后自己上传,上传的时候,有一个进度条,上传完之后,预览图片。

同时,在Huploadify基础上,还增加了单个图片上传,比如在上传头像的时候,不可能让你上传多张图片。

因此,我在Huploadify的基础上进行修改,得到了HHuploadify。

HHuploadify的用法和Huploadify的用法是一模一样的。不过增加了几个点:

  1. 增加isSingle配置项,在初始化的时候,如果isSingle=true,那么这个上传只能上传一张图片。domo.html中有案例
  2. 增加了上传图片结束后,将图片显示到该上传区域中预览,返回格式必须是json,有一个url字段。upload.php中有案例

修改样式:通过修改HHuploadify.css文件中的样式来控制表现。

上传后得到的图片预览是通过将图片作为该区域的背景图片实现的,因此,如果要调整该图片,必须通过css来进行控制。

2016-01-19 13-43-52屏幕截图

安装

获取代码:从我的github上下载HHuploadify的源代码。

首先,你的网页中得引入jquery

<script src="jquery-2.2.0.min.js"></script>

其次,再网页中引入插件文件

<script src="jquery.HHuploadify.js"></script>

再次,再网页头部引入HHuploadify的样式文件

<link rel="stylesheet" href="HHuploadify.css">

如果你想对HHuploadify的样式进行修改,可以修改HHuploadify.css文件中的具体规则,改完之后,把上面的地址改为HHuploadify.css,从而使用新的样式。当然,你也可以把里面的样式全部拷贝出来,放到自己的样式文件里面去,这样就可以不用引用HHuploadify.css。

使用

上传多张(一组)图片

HHuploadify会初始化一个按钮,让你进行上传。因此,在你需要展示这个按钮的地方做如下操作。假如你想调用的容器为<div id="upload"></div>,只需要在网页底部加入如下代码:

<script>
    $('#upload').HHuploadify({
        fileTypeExts:'*.jpg;*.png;*.gift',
        uploader:'upload.php' // 必须的,必须指定用来处理上传逻辑的后端处理URL
    });
</script>

这样,就可以初始化一个按钮,点击按钮之后可以多选多张图片,每张图片会各自提交到upload.php。这里提示一下,uploadify本身就是一张一张图片提交的,而不是所有图片一起提交。upload.php可以是你自己的URL,在这个URL进行图片处理和保存,并且返回一个包含url字段的json字符串,通过这个url字段让上传区域展示图片。

单张片上传

你可能现在想上传一张头像图片,先把css改为你想要的结果。在上面的代码中,只需要加入一个isSingle参数即可:

<script>
    $('#upload').HHuploadify({
        fileTypeExts:'*.jpg;*.png;*.gift',
        isSingle:true,
        uploader:'upload.php'
    });
</script>

这样,这个区域只能进行一张图片的上传。

多张图片上传的时候,无论你上传了多少张图片,末尾都会存在选择图片的按钮,你还可以继续上传。而单张图片上传时,选择图片时只能选择一张,选择好之后就进入上传状态,按钮消失,不能继续选择图片进行上传。

在文章开头的展示图片中,第一个区域内有两张封面图,它们就是用单张图片实现的,你可以看到,图片上传成功后,看不到上传按钮。而第二个区域的展示图片列表,就是多张图片实现的,可以看到有上传按钮。

初始化参数

fileTypeExts:'*.*',//允许上传的文件类型,格式'*.jpg;*.doc'
uploader:'',//文件提交的地址
auto:true,//是否开启自动上传
method:'post',//发送请求的方式,get或post
multi:true,//是否允许选择多个文件
isSingle:false,// 是否是单个文件上传,如果是单个文件上传,选择文件后,上传按钮会消失,multi也会被强制设定为false
formData:null,//发送给服务端的参数,格式:{key1:value1,key2:value2}
fileObjName:'file',//在后端接受文件的参数名称,如PHP中的$_FILES['file']
fileSizeLimit:2048,//允许上传的文件大小,单位KB
showUploadedFilename:false,//是否显示上传文件名
showUploadedPercent:false,//是否实时显示上传的百分比,如20%
showUploadedSize:false,//是否实时显示已上传的文件大小,如1M/2M
buttonText:'选择文件',//上传按钮上的文字
itemTitle:false,// 该上传item区域的标题:该值将作为上传按钮的提示语,上传时,会显示在左上角,注意,每一个上传区都会有,所以尽可能再isSingle=true的情况下使用
removeTimeout: 1000,//上传完成后进度条的消失时间,单位毫秒
itemTemplate:itemTemp,//上传队列显示的模板
onUploadStart:null,//上传开始时的动作
onUploadSuccess:null,//上传成功的动作
onUploadComplete:null,//上传完成的动作
onUploadError:null, //上传失败的动作
onInit:null,//初始化时的动作
onCancel:null,//删除掉某个文件后的回调函数,可传入参数file
onClearQueue:null,//清空上传队列后的回调函数,在调用cancel并传入参数*时触发
onDestroy:null,//在调用destroy方法时触发
onSelect:null,//选择文件后的回调函数,可传入参数file
onQueueComplete:null//队列中的所有文件上传完成后触发

以上是HHuploadify的所有默认初始化参数,除了isSingle、itemTitle以外,其他所有的都是和Huploadify一样的,只不过我修改了它的默认值。isSingle前面已经通过代码讲解过了,itemTitle则是文章开头的那张展示图片中“大封面图”“小封面图”两个文字提示,该提示会漂浮在区域的左上角。

具体文档请阅读Huploadify

例子

上传图片后提交保存相册

现在模拟用HHuploadify来做一个相册。用户先创建了一个相册A,多选图片,上传到该相册,图片全部由数据库保存URL,并有对应的ID,现在要求,有一个相册和图片的关系数据表album_photo_relation用来保存哪一张图片属于哪一个相册。那么问题来了,如何在上传图片的时候实现这个过程呢?

很简单,在初始化参数中增加formData参数,比如:

<script>
    $('#upload').HHuploadify({
        fileTypeExts:'*.jpg;*.png;*.gift',
        formData: {album_id: <?=$album_id?>},
        uploader:'upload.php'
    });
</script>

在upload.php中就能接收到该相册的ID:$_POST['album_id']。这样,在upload.php中就可以在插入完photo获得photo_id后,再向alubm_photo_relation表中插入一条记录。

现在问题又来了,加入要求不允许先创建相册、进入相册再上传,现在要求相册创建时先上传图片,上传完之后,和相册信息(如名称、描述等)一同提交到create_album.php。

这就复杂了,因为不能通过formData,直接在upload.php中完成每一张图片的操作。怎么办呢?我的解决办法是,在图片上传完成后,将图片的photo_id加载到当前的页面里面,提交创建相册的时候,同时可以知道该相册有哪些图片。

<script>
    $('#upload').HHuploadify({
        fileTypeExts:'*.jpg;*.png;*.gift',
        uploader: 'upload.php',
        onUploadSuccess: function(file,data) {
            var photo = JSON.parse(data);
            var photo_id = photo.id;
            var instanceNumber = $('.uploadify').length+1;
            var file_index = file.index;
            $('#fileupload_' + instanceNumber + '_' + file_index).append('<input type="hidden" name="photo_id[]" value="' + photo_id + '">');
        }
    });
</script>

上面的代码主要利用到了onUploadSuccess事件,及当一张图片上传成功之后的回调。这样,在删除的时候,可以删除掉对应的input,在提交的时候,可以提交对应的photo_id[]。

上传完图片后可对图片进行拖动排序

在相册的案例中,有一种情况是,还可以对图片进行拖动,调整图片组的顺序。怎么实现呢?首先你得有一个能够实现拖动的jquery插件,我推荐DragSort

<script src="jquery.dragsort-5.2.0.min.js"></script>
<script>
$('#upload').HHuploadify({
    fileTypeExts:'*.jpg;*.png;*.gift',
    uploader:'upload.php',
    onQueueComplete:function() {
        var instanceNumber = $('.uploadify').length+1;
        var $instance = $('#file_upload_' + instanceNumber + '-queue');
        $instance.dragsort("destroy");
        $instance.dragsort({
                dragSelector: "div.uploadify-queue-item",
                dragBetween: true,
                dragEnd: function(){
                    $instance.find('.uploadify-queue-item').removeAttr('style');
                },
                placeHolderTemplate: '<div class="uploadify-queue-item"></div>'
            });
    }
});
</script>

上面的代码通过一个onQueueComplate事件绑定,在所有文件上传结束后,执行函数中的动作。函数中的动作可以使该区域内的所有图片区域绑定dragsort,实现拖动排序的功效。

扩展函数

为了实现更简洁的载入,我新增了HHuploadifyReady.js,里面有initHHuploadify函数和resetHHuploadify函数。

载入:initHHuploadify

function initHHuploadify(selector,uploader,field,isSingle,title)

selector是要初始化的选择器,uploader是上传后端处理URL,field是回调的时候,往区域内插入的input的name值,注意,插入的input name=field[],提交的是一个数组,后端应该注意一下。isSingle就不解释了,表示是否单个图片上传,当为true时,input name=field,不是数组。title则是上文提到的itemTitle初始化参数,但是设置了title之后,上传按钮的提示也会有所变化,你可以自己观察。

为了便于使用,一般再使用的时候,你可以不设置第四个参数,而是使用下面这个函数:

function initHHuploadifyOne(selector,uploader,field,title)

这个函数是从上面的函数衍生出来的,不用传第四个参数,即可让HHuploadify初始化为一个只能上传一张图片的区域。

为了更加方便的构建固定的上传列表,在initHHuploadifyOne的基础上,构建多个图片上传区域:

function initHHuploadifyCount(selector,uploader,fields,titles)

这里的Count和One是对应的,One代表一个,而Count代表多个,实际上是One的重复。我们用一段代码来看下对比:

<script>
initHHuploadifyOne('#upload','upload.php','coverImage','封面图'); // 将在#upload中载入一个上传区域,为单张图片上传模式
initHHuploadifyCount(
    '#upload2','upload.php',
    ['coverImageBig','coverImageSmall'],
    ['大封面图','小封面图']
); // 将在#upload2中载入两个上传区域,每个上传区域都是单张图片上传模式 // 注意第三个参数和第四个参数,它们是一一相对的
</script>

通过这个演示,你应该可以知道它的区别,如果还有所疑虑,可以自己测试。

重载:resetHHuploadify

当完成初始化之后,你会发现,有的时候你的页面上需要放置几张图片进去,比如在编辑相册的时候,你的相册中本身已经存在了一些图片了,所以你在编辑它的时候,必须让相册中的图片都显示出来,这个时候,需要用resetHHuploadify来实现。

function resetHHuploadify(selector,images,field,title)

它有三个参数,selector和前面的一样,都是指初始化时的对象选择器,例如$(selector)在前面的案例中就是$('#upload')。images是一个对象数组,包含了要用于显示的图片信息,首先它是一个数组,其次它的每一个元素又是对象,形式如下:

[{'id' => 4,'url' => '/images/afa.jpg'},{'id' => 56,'url' => '/images/aafdsfa.jpg'},{'id' => 12,'url' => '/images/12fa.jpg'}]

为什么要这样呢?id是用来作为input的value值的,url是用来展示图片的,就是这样。field则是input的name值,注意,由于是多个input,所以它也是input name=field[],是个数组,后端接收的时候要注意。

不过在resetHHuploadify的基础上,也衍生出了resetHHuploadifyOne,单张图片上传模式:

function resetHHuploadifyOne(selector,image,field,title)

唯一的区别在于第二个参数,由images变为image,不是一个数组,而是一个对象,形式如下:

{'id' => 56,'url' => '/images/aafdsfa.jpg'}

只有一张图片的信息。

既然有One,那么就有Count咯:

function resetHHuploadifyCount(selector,images,fields,titles)

你可以看到,我标了红。因为Count函数是基于One函数的,所以实际上,它是多次重复One函数来载入多个区域的内容,所以它的参数一定是数组,而且具有一一对应的要求,images的长度多少,另外两个的长度也必须是多少。而且还有一点,reset相关函数的载入数量,还需要和init所载入的区域个数一样(reset一定是跟在init后面的)。

OK,对HHuploadify的推介就到这里了,如果你有不懂的地方,欢迎到我的github去提交issue,这样子显得专业一点。

Demo

2016-01-18

已有9条评论
  1. 高军 2016-09-01 20:38

    测试安卓手机上,获取不到图片的路径!是为什么 – -您好

    • 否子戈 2016-09-01 21:50

      手机上没试过。如果有问题,在github上给我提issue吧。

  2. 高军 2017-02-14 11:46

    上传是默认图片,怎么修改成动态的?就比如修改用户头像,默认图片讲就是用户的头像、

  3. spip 2017-03-10 11:32

    你好,看本文是示例截图有最多7张的限制,但是源码中并未找到,请问如何设置呢?

    • 否子戈 2017-03-10 22:00

      具体我也忘记了,可能是在具体的产品里面实现了这个功能。不过我看到有一个onSelect的初始化参数,你可以在这个参数函数中对其进行控制,超出了某个值,就从列表中把多余的那个图片给移除掉。

  4. Ivan 2017-03-13 13:15

    能不能默认设置一个背景图作为背景

    • 否子戈 2017-03-13 14:36

      可以通过css来设置

  5. 咨询 2017-05-09 17:21

    请教一下:我现在又这么个情况:我的图片上传框是动态添加的,每个都类似:

    我怎么把服务器返回值给填到对应的input值上去?

    • 否子戈 2017-05-09 18:40

      服务端返回的值格式有要求,你再看下文档