有人能解释一下如何实现jQuery文件上传插件吗?

126

编辑(2019年10月):

6年过去了,jQuery文件上传显然仍然让人们抓狂。如果你在这里找不到什么安慰,试试NPM搜索一个现代的替代方案。我保证它不值得麻烦。

在上一次修改中,我推荐使用Uploadify,但正如评论者指出的那样,他们似乎不再提供免费版本了。Uploadify已经太过时了


编辑:

由于仍有流量过来,所以我会解释我最终是怎么做的。我最终通过遵循接受答案中的教程使插件工作。但是,jQuery文件上传非常麻烦,如果你正在寻找一个更简单的文件上传插件,我强烈推荐 [Uploadify](http://www.uploadify.com)。正如一个回答指出的,它只适用于非商业用途。


背景

我正在尝试使用blueimp的jQuery文件上传来允许用户上传文件。 开箱即用,按照设置说明运行得非常完美。但是为了在我的网站上实际使用它,我想能够做一些事情:

  • 在我的任何现有页面中包含上传程序
  • 更改上传文件的目录

插件的所有文件都位于根目录下的一个文件夹中。

我试过...

  • 将演示页面移动到根目录并更新必要脚本的路径
  • 此处所建议的更改UploadHandler.php文件中的“upload_dir”和“upload_url”选项。
  • 更改演示javascript第二行中的URL

在所有情况下,预览显示,进度条运行,但文件未能上传,并出现此控制台错误:Uncaught TypeError: Cannot read property 'files' of undefined。我不理解插件的所有部分是如何工作的,这使得调试变得困难。

代码

演示页面中的javascript:

$(function () {
'use strict';
// Change this to the location of your server-side upload handler:
var url = 'file_upload/server/php/UploadHandler.php',
    uploadButton = $('<button/>')
        .addClass('btn')
        .prop('disabled', true)
        .text('Processing...')
        .on('click', function () {
            var $this = $(this),
                data = $this.data();
            $this
                .off('click')
                .text('Abort')
                .on('click', function () {
                    $this.remove();
                    data.abort();
                });
            data.submit().always(function () {
                $this.remove();
            });
        });
$('#fileupload').fileupload({
    url: url,
    dataType: 'json',
    autoUpload: false,
    acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
    maxFileSize: 5000000, // 5 MB
    // 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.userAgent),
    previewMaxWidth: 100,
    previewMaxHeight: 100,
    previewCrop: true
}).on('fileuploadadd', function (e, data) {
    data.context = $('<div/>').appendTo('#files');
    $.each(data.files, function (index, file) {
        var node = $('<p/>')
                .append($('<span/>').text(file.name));
        if (!index) {
            node
                .append('<br>')
                .append(uploadButton.clone(true).data(data));
        }
        node.appendTo(data.context);
    });
}).on('fileuploadprocessalways', function (e, data) {
    var index = data.index,
        file = data.files[index],
        node = $(data.context.children()[index]);
    if (file.preview) {
        node
            .prepend('<br>')
            .prepend(file.preview);
    }
    if (file.error) {
        node
            .append('<br>')
            .append(file.error);
    }
    if (index + 1 === data.files.length) {
        data.context.find('button')
            .text('Upload')
            .prop('disabled', !!data.files.error);
    }
}).on('fileuploadprogressall', function (e, data) {
    var progress = parseInt(data.loaded / data.total * 100, 10);
    $('#progress .bar').css(
        'width',
        progress + '%'
    );
}).on('fileuploaddone', function (e, data) {
    $.each(data.result.files, function (index, file) {
        var link = $('<a>')
            .attr('target', '_blank')
            .prop('href', file.url);
        $(data.context.children()[index])
            .wrap(link);
    });
}).on('fileuploadfail', function (e, data) {
    $.each(data.result.files, function (index, file) {
        var error = $('<span/>').text(file.error);
        $(data.context.children()[index])
            .append('<br>')
            .append(error);
    });
}).prop('disabled', !$.support.fileInput)
    .parent().addClass($.support.fileInput ? undefined : 'disabled');
});
我对缺乏文档感到惊讶,这似乎应该是一个简单的更改。如果有人能够解释如何做到这一点,我将不胜感激。

10
良好的问题格式。看到组织性很好。 - jdero
在错误行的前面,在控制台中打印出'e'和'data',它们的值是什么? - john 4d5
3
Uploadify采用MIT许可证,也就是完全免费。而来自同一开发者/网站的UploadiFive根据使用情况收费$5至$100。 - MartinJH
2
两年来,jQuery-File-Upload的文档没有任何改进。唉。 - Chuck Le Butt
2
@MartinJH,可能曾经有过一个uploadify版本,但现在只有一个付费的uploadiFive版本。而且也没有演示;只有一个视频。这样做很不好。 - Steve Horvath
显示剩余2条评论
11个回答

74

几天前,我正在寻找类似的功能,并在tutorialzine上找到了一篇不错的教程。这里有一个工作示例。完整的教程可以在这里找到。

一个简单的表格来容纳文件上传对话框:

<form id="upload" method="post" action="upload.php" enctype="multipart/form-data">
  <input type="file" name="uploadctl" multiple />
  <ul id="fileList">
    <!-- The file list will be shown here -->
  </ul>
</form>

这是上传文件的 jQuery 代码:

$('#upload').fileupload({

  // This function is called when a file is added to the queue
  add: function (e, data) {
    //This area will contain file list and progress information.
    var tpl = $('<li class="working">'+
                '<input type="text" value="0" data-width="48" data-height="48" data-fgColor="#0788a5" data-readOnly="1" data-bgColor="#3e4043" />'+
                '<p></p><span></span></li>' );

    // Append the file name and file size
    tpl.find('p').text(data.files[0].name)
                 .append('<i>' + formatFileSize(data.files[0].size) + '</i>');

    // Add the HTML to the UL element
    data.context = tpl.appendTo(ul);

    // Initialize the knob plugin. This part can be ignored, if you are showing progress in some other way.
    tpl.find('input').knob();

    // Listen for clicks on the cancel icon
    tpl.find('span').click(function(){
      if(tpl.hasClass('working')){
              jqXHR.abort();
      }
      tpl.fadeOut(function(){
              tpl.remove();
      });
    });

    // Automatically upload the file once it is added to the queue
    var jqXHR = data.submit();
  },
  progress: function(e, data){

        // Calculate the completion percentage of the upload
        var progress = parseInt(data.loaded / data.total * 100, 10);

        // Update the hidden input field and trigger a change
        // so that the jQuery knob plugin knows to update the dial
        data.context.find('input').val(progress).change();

        if(progress == 100){
            data.context.removeClass('working');
        }
    }
});
//Helper function for calculation of progress
function formatFileSize(bytes) {
    if (typeof bytes !== 'number') {
        return '';
    }

    if (bytes >= 1000000000) {
        return (bytes / 1000000000).toFixed(2) + ' GB';
    }

    if (bytes >= 1000000) {
        return (bytes / 1000000).toFixed(2) + ' MB';
    }
    return (bytes / 1000).toFixed(2) + ' KB';
}

以下是用于处理数据的PHP代码示例:

if($_POST) {
    $allowed = array('jpg', 'jpeg');

    if(isset($_FILES['uploadctl']) && $_FILES['uploadctl']['error'] == 0){

        $extension = pathinfo($_FILES['uploadctl']['name'], PATHINFO_EXTENSION);

        if(!in_array(strtolower($extension), $allowed)){
            echo '{"status":"error"}';
            exit;
        }

        if(move_uploaded_file($_FILES['uploadctl']['tmp_name'], "/yourpath/." . $extension)){
            echo '{"status":"success"}';
            exit;
        }
        echo '{"status":"error"}';
    }
    exit();
}

以上代码可以添加到任何现有的表单中。一旦添加了图像,该程序会自动上传图像。您可以更改此功能,并且在提交现有表单时也可以提交图像。

已更新我的答案,包括实际代码。所有信用归原始代码作者所有。

来源: http://tutorialzine.com/2013/05/mini-ajax-file-upload-form/


2
你能把那个教程的重要部分复制到这里吗?这样即使它消失了,你的回答仍然有用。 - user764357
1
但请注意不要剽窃。 - tacaswell
1
注意:对于使用 PHP 代码片段的任何人,请删除 if($_POST) 语句。POST 应该是空的,文件内容发送在 $_FILES['upfile']['tmp_name'] 中。希望这能为某些人节省时间。 - Edward
1
发现另一个http://www.c-sharpcorner.com/UploadFile/da55bf/multiple-files-upload-using-jquery-ajax-and-jqueryui-progres/。 - Rush.2707
有人能建议我运行上述脚本需要哪些js/jquery文件吗? - Manasa
显示剩余4条评论

31

我刚花了两个小时来折腾jQuery Upload,但因为依赖项太多(我必须包含13个JS文件才能获取所有功能),所以放弃了。

我继续搜索后发现一个很不错的项目叫做Dropzone.js,它没有任何依赖项。

作者还创建了一个bootstrap演示项目,灵感来源于jQuery文件上传插件。

希望这能帮助别人节省时间。


1
需要注意的重要事项:Dropzone.js看起来很不错,但它只支持IE10及更高版本。而jQuery文件上传则支持IE6及更高版本 ;) - Nickvda
11
jQuery文件上传无论如何都无法让它工作...我花了许多时间尝试,因为它有非常好的功能,但在最后一刻我的灵魂只被痛苦填满!!!太绝望了!!!然后我看到了你关于Dropzone.js的帖子,在5分钟内我使它工作并且以我想要的方式!你救了我... - rigon
无法感谢你的足够,我花了近12个小时来让jQuery-File-Upload按我的要求工作,最终我偶然发现了这个问题。你救了我。 - ndd
这是一个基于数据库的jQuery文件上传示例:https://github.com/CodeHeight/ImageLibrary - JoshYates1980
我花了三天的时间,但我仍然无法定制他们的代码。 - May'Habit
确实很有帮助,我花了近8个小时来尝试自定义jQuery文件上传。 - logicalrap

4

我也曾为此苦恼,但是一旦我弄清楚了UploadHandler.php中路径的工作方式,就解决了这个问题:upload_dir和upload_url是唯一需要查看的设置来使其正常工作。此外,检查服务器错误日志以获取调试信息。


3
请查看使用Dropper jQuery插件的图像拖放上传器和图像预览。 HTML
<div class="target" width="78" height="100"><img /></div>

JS

$(".target").dropper({
    action: "upload.php",

}).on("start.dropper", onStart);
function onStart(e, files){
console.log(files[0]);

    image_preview(files[0].file).then(function(res){
$('.dropper-dropzone').empty();
//$('.dropper-dropzone').css("background-image",res.data);
 $('#imgPreview').remove();        
$('.dropper-dropzone').append('<img id="imgPreview"/><span style="display:none">Drag and drop files or click to select</span>');
var widthImg=$('.dropper-dropzone').attr('width');
        $('#imgPreview').attr({width:widthImg});
    $('#imgPreview').attr({src:res.data});

    })

}

function image_preview(file){
    var def = new $.Deferred();
    var imgURL = '';
    if (file.type.match('image.*')) {
        //create object url support
        var URL = window.URL || window.webkitURL;
        if (URL !== undefined) {
            imgURL = URL.createObjectURL(file);
            URL.revokeObjectURL(file);
            def.resolve({status: 200, message: 'OK', data:imgURL, error: {}});
        }
        //file reader support
        else if(window.File && window.FileReader)
        {
            var reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onloadend = function () {
                imgURL = reader.result;
                def.resolve({status: 200, message: 'OK', data:imgURL, error: {}});
            }
        }
        else {
            def.reject({status: 1001, message: 'File uploader not supported', data:imgURL, error: {}});
        }
    }
    else
        def.reject({status: 1002, message: 'File type not supported', error: {}});
    return def.promise();
}

$('.dropper-dropzone').mouseenter(function() {
 $( '.dropper-dropzone>span' ).css("display", "block");
});

$('.dropper-dropzone').mouseleave(function() {
 $( '.dropper-dropzone>span' ).css("display", "none");
});

CSS

.dropper-dropzone{
    width:78px;
padding:3px;
    height:100px;
position: relative;
}
.dropper-dropzone>img{
    width:78px;
    height:100px;
margin-top=0;
}

.dropper-dropzone>span {
    position: absolute;
    right: 10px;
    top: 20px;
color:#ccc;


}

.dropper .dropper-dropzone{

padding:3px !important    
}

Demo Jsfiddle


这是一个非常简单的解决方案。 - Miron

2

这是一个很好的用于上传文件的Angular插件,而且是免费的!

angular文件上传


2
嗨。请不要将链接作为答案发布,如果该网站离线或链接更改,您的答案将变得无用。相反,使用网站上的信息来构建您的答案,并仅将链接用作参考。谢谢。 - Cthulhu

1

现在是2021年,这里有一个非常易用的插件可以上传任何东西:

https://pqina.nl/filepond/?ref=pqina

添加你的元素:
<input type="file" 
class="filepond"
name="filepond" 
multiple 
data-allow-reorder="true"
data-max-file-size="3MB"
data-max-files="3">

注册任何其他插件:

  FilePond.registerPlugin(
FilePondPluginImagePreview,  
FilePondPluginImageExifOrientation,  
FilePondPluginFileValidateSize,  
FilePondPluginImageEdit);

然后将元素连接起来:
// Select the file input and use 
// create() to turn it into a pond
FilePond.create(
  document.querySelector('input'),

  // Use Doka.js as image editor
  imageEditEditor: Doka.create({
    utils: ['crop', 'filter', 'color']
  })
);

我使用这个额外的Doka图像编辑器来上传和转换图片,网址是https://www.yoodu.co.uk

设置非常简单,运营团队提供了出色的支持。

正如你所看到的,我是一个粉丝。


1

Droply.js非常适合这个需求。它简单易用,并且预装了一个演示网站,可以直接使用。


1

我在Rails上使用这个插件挣扎了一段时间,然后有人将其打包成gem,使我所创建的所有代码都过时了。

虽然看起来你没有在Rails中使用它,但如果有人正在使用,请检查这个gem。源代码在这里-->jQueryFileUpload Rails

更新:

为了满足评论者的要求,我更新了我的答案。基本上是"使用这个gem, 这是源代码"。如果它消失了,那就采用长方法。


1
你可以使用uploadify这个是我用过的最好的多文件上传jQuery插件。
实现很简单,浏览器支持也非常好。

2
你可以使用HTML 5版本 :) - CORSAIR
5
如果我没记错的话,Uploadify 的 HTML5 版本是需要付费的,价格为 $5。详情请访问 http://www.uploadify.com/download/。 - kingsfoil
2
但是,这只有5美元,不是500美元。 - CORSAIR
7
请注意,如果您想将uploadify用于商业目的,您需要购买商业许可证(100美元)。可以从此链接:http://www.uploadify.com/download/download-uploadifive-commercial/ - Tim
2
对于任何感兴趣的人,Uploadify = Flash版本,UploadiFive = HTML5版本。 - Chuck Le Butt
显示剩余2条评论

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接