我写了一个脚本,通过拖放使用jQuery上传文件,jQuery在drop上读取文件并将其添加到文件数组中,如下所示:
var files = []; $(document).ready(function() { jQuery.fn.dropbox = function(config) { var dragging = 0; var dragEnter = function(e) { e.stopPropagation(); e.preventDefault(); dragging++; $(".external-drop-indicator").fadeIn(); $(".toast.toast-success").fadeIn().css("display", "inline-block");; return false; }; var dragOver = function(e) { e.stopPropagation(); e.preventDefault(); return false; }; var dragLeave = function(e) { e.stopPropagation(); e.preventDefault(); dragging--; if(dragging === 0) { $(".external-drop-indicator").fadeOut(); $(".toast.toast-success").fadeOut(); } return false; }; var drop = function(e) { var dt = e.dataTransfer; var files_upload = dt.files; e.stopPropagation(); e.preventDefault(); if(files_upload && files_upload.length > 0 && config.onDrop !== undefined) { files.push(files_upload); config.onDrop(files_upload); } $(".external-drop-indicator").fadeOut(); $(".toast.toast-success").fadeOut(); }; var applyDropbox = function(dropbox) { dropbox.addEventListener('dragenter', dragEnter, false); dropbox.addEventListener('dragover', dragOver, false); dropbox.addEventListener('dragleave', dragLeave, false); dropbox.addEventListener('drop', drop, false); }; return this.each(function() { applyDropbox(this); }); }; });
总结它的作用是,添加一个扩展的jQuery函数,以便在应用该函数的网站的某个元素上进行拖放.
然后我将扩展功能应用到主体,以启用文件拖放功能,如下所示:
$(document).ready(function() { $('body').dropbox({ onDrop: function(f) { $(f).each(function(idx, data) { var file_name = data.name; var extension = file_name.split('.'); file_name = extension[0]; extension = extension[1]; if(extension == 'pdf' || extension == 'xls') { showAjaxModal(base_url + 'index.php?modal/popup/file_create/' + folder_id + '/' + extension + '/' + file_name); } else { $(".upload-area").append('Error! File type is incorrect.'); } }); } }); });
总之,它的作用是将拖放功能添加到正文中,当文件被删除时,它会通过拆分名称和扩展名来检测文件的扩展名,以便我可以验证丢弃的文件的扩展名是正确的.然后,如果文件扩展名正确,则继续显示模式以填充有关正在上载以供稍后提交的文件的信息.
然后我继续使用CodeIgniter的函数"form_open()"填充文件信息,当模态弹出如下:
'form-horizontal form-groups-bordered validate ajax-upload', 'enctype' => 'multipart/form-data')); ?>
这基本上创建了一个表单,稍后将通过Ajax提交.
现在我继续通过jQuery处理文件提交,以便与要上传的文件或文件一起发送信息,如下所示:
$(document).ready(function(e) { $('.ajax-upload').submit(function(e) { e.preventDefault(); var $elm = $(this); var fd = new FormData(); for(var i = 0; i < files.length; i++) { fd.append("file_" + i, files[i]); } var form_data = $(".ajax-upload").serializeArray(); $.each(form_data, function(key, input) { fd.append(input.name, input.value); }); var opts = { url: $elm.attr('action'), data: fd, cache: false, contentType: false, processData: false, type: 'POST', beforeSend: uValidate, success: showResponse }; if(fd.fake) { opts.xhr = function() { var xhr = jQuery.ajaxSettings.xhr(); xhr.send = xhr.sendAsBinary; return xhr; } opts.contentType = "multipart/form-data; boundary=" + fd.boundary; opts.data = fd.toString(); } jQuery.ajax(opts); return false; }); });
基本上,表单默认操作被覆盖,并且在先前的代码块上提交的用于拖放功能的文件现在附加到formData,后者通过我提交的表单上的表单数据加入.然后通过AJAX调用发送formData.
现在控制器看起来像这样,它处理AJAX调用,然后在模型上执行文件上载方法,如下所示:
function file($param1 = '', $param2 = '', $param3 = 0) { if ($this->session->userdata('client_login') != 1) { $this->session->set_userdata('last_page', current_url()); redirect(base_url(), 'refresh'); } if ($param1 == 'create') $this->crud_model->create_file($param2); if ($param1 == 'edit') $this->crud_model->update_file($param2); if ($param1 == 'delete') $this->crud_model->delete_file($param2, $param3); $page_data['page_name'] = 'files'; $page_data['page_title'] = 'Files List'; $page_data['folder_id'] = $param3; $this->load->view('backend/index', $page_data); }
这是模型方法:
function create_file($folder_id) { $data['name'] = $this->input->post('name'); $data['tags'] = $this->input->post('tags'); $data['description'] = $this->input->post('description'); $data['type'] = 'file'; $data['folder_id'] = $folder_id; $data['client_id'] = $this->session->userdata('login_user_id'); $config['upload_path'] = 'uploads/tmp/'; $config['allowed_types'] = '*'; $config['max_size'] = '100'; $this->load->library('upload'); $this->upload->initialize($config); var_dump($_FILES); die(); foreach($_FILES as $field => $file) { //var_dump($_FILES); die(); // No problems with the file if($file['error'] == 0) { // So lets upload if ($this->upload->do_upload($field)) { $data = $this->upload->data(); echo $data['full_path']; } else { $errors = $this->upload->display_errors(); var_dump($errors); } } } $this->db->insert('client_files' , $data); }
所以基本上会发生的是$ _FILES数组是空的,并且文件没有上传.
在Chrome开发者工具上查看的"请求有效负载"如下所示:
------WebKitFormBoundaryvVAxgIQd6qU8BtkF Content-Disposition: form-data; name="file_0" [object FileList] ------WebKitFormBoundaryvVAxgIQd6qU8BtkF Content-Disposition: form-data; name="tags" bsd ------WebKitFormBoundaryvVAxgIQd6qU8BtkF Content-Disposition: form-data; name="name" asd ------WebKitFormBoundaryvVAxgIQd6qU8BtkF Content-Disposition: form-data; name="description" asd
我从模型上的var_dump()得到的响应如下:
array(0) { }
我已经尝试过这个问题的解决方案:用jQuery.ajax发送multipart/formdata但到目前为止还没有运气.
我知道自己做错了什么以及如何解决这个问题?谢谢.
这里的问题是我在AJAX调用中发送文件数组而不是单个文件,特别是在这部分代码中:
for(var i = 0; i < files.length; i++) { fd.append("file_" + i, files[i]); }
解决方案是逐个文件追加到formData而不是文件数组,如下所示:
for(var i = 0; i < files[0].length; i++) { fd.append("file_" + i, files[i]); }
这将附加文件数组的每个文件而不是文件数组本身,它解决了问题.
总而言之,我发送的是文件数组而不是单个文件,这就是[object FileList]
请求显示而不是文件信息的线索,现在这样做的请求是这样的:
Content-Disposition: form-data; name="file"; filename="exfile.pdf" Content-Type: application/pdf