上个月写过一篇WordPress通过Rest API自定义附件上传接口,那篇文章主要介绍了如何打通前后端,利用Rest API保存“抓取”已知URL的文件。不过在更多的情况下,我们还是需要通过自己的表单上传文件。正好这个月有个项目,有个表单需要拖放文件到指定区域里,提交表单的时候上传文件。如果我用Gravity Forms给的文件上传域,它只有原生的点击选取本地的文件组件,并没有拖放选取文件的组件,所以这里就需要造一个轮子了。
先说结果,最后实现出来是这样子的:
文件拖到区域上方,区域会变色;拖入后区域内显示文件名,判断文件格式和尺寸是否合规;点击清除,会重置区域。
HTML结构:
这里面#pro_document这个就是真实的用来上传的输入项,把它隐藏,通过JS使.js-drag整个区域可以接受拖放文件进来。
1 2 3 4 5 6 7 | <div class="dragarea js-drag"> <p>DRAG A FILE HERE,<br/>OR</p> <span class="js-drag-fileinfo"></span> <a href="###" class="button">Choose a File</a> <a href="###" class="js-drag-clear">x Clear</a> <input type="file" value="" name="pro_document" id="pro_document" placeholder="" class="js-drag-file" /> </div> |
JS部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | $(function(){ //允许的格式 var fileTypeArray = ['JPG','PNG','CAD','RAR','ZIP']; function FileListItems (files) { var b = new ClipboardEvent("").clipboardData || new DataTransfer() for (var i = 0, len = files.length; i<len; i++) b.items.add(files[i]) return b.files } function FileVerify(file){ if(file.size > 2*1024*1024){ alert("文件不能大于2M"); return false; }else if(file.size <= 0){ alert("文件大小不能小于0"); return false; }else{ var arr = file.name.split('.'); var suffix = arr[arr.length-1].toUpperCase(); if(fileTypeArray.includes(suffix)){ return true; }else { alert("暂时不支持" + suffix + "格式文件"); return false; } } } var dragElement = $('.js-drag'); //拖入结束 $('.js-drag').on("drop", function(event){ event.preventDefault(); event.stopPropagation(); var fileFieldDOM = $(this).find('.js-drag-file')[0]; var fileFieldDisplay = $(this).find('.js-drag-fileinfo'); console.log(event); event.dataTransfer = event.originalEvent.dataTransfer; var firstFile = event.dataTransfer.files[0]; var firstFileArr = [ firstFile ]; var newfileList = new FileListItems(firstFileArr); if( FileVerify(firstFile)){ console.log("file verified: "+ firstFile.name); console.log(firstFile); //.filled样式追加后,区域变成已添加文件的状态 $(this).addClass("filled") fileFieldDisplay.html("selected file:</br>" + firstFile.name); fileFieldDOM.files= newfileList; } $(this).removeClass("dragenter"); }); //点击开启选择文件窗口 $('.js-drag').on("click", function(event){ var fileFieldDOM = $(this).find('.js-drag-file')[0]; var fileFieldDisplay = $(this).find('.js-drag-fileinfo'); fileFieldDOM.click(); }); //拖入 $('.js-drag').on("dragenter", function(event){ event.preventDefault(); event.stopPropagation(); //console.log('dragenter'); //增加样式.dragenter,其实就是一个背景色,以提示用户有文件正在拖进来 $(this).addClass("dragenter"); }); //文件正在区域上方 $('.js-drag').on("dragover", function(event){ event.preventDefault(); event.stopPropagation(); }); //拖离 $('.js-drag').on("dragleave", function(event){ //console.log('dragleave'); $(this).removeClass("dragenter"); }); //所选的文件改变 $('.js-drag-file').on("change",function(event){ var firstFile = $(this)[0].files[0]; if( FileVerify(firstFile)){ console.log("file verified: "+ firstFile.name); console.log(firstFile); $(this).parent().addClass("filled"); $(this).siblings('.js-drag-fileinfo').html("selected file:</br>" + firstFile.name); }else{ $(this)[0].files=new FileListItems(""); } }); //清空选定的文件 $('.js-drag-clear').on("click",function(event){ event.preventDefault(); event.stopPropagation(); $(this).siblings('.js-drag-file')[0].files=new FileListItems(""); $(this).siblings('.js-drag-fileinfo').html(""); $(this).parent().removeClass("filled"); }); }); |
样式表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | .form-regular .dragarea{ box-sizing: border-box; width: 100%; height: 150px; background:#f7f7f7; border-radius: 6px; border:2px dashed #d3d3d3; display: flex; flex-direction: column; flex-wrap: nowrap; justify-content:center; font-size: 13px; text-align: center; } .form-regular .dragarea.dragenter{ background:#dedede; } .form-regular .dragarea p{ font-size: 13px; margin:0 auto 6px auto; line-height: 1.3; } .form-regular .dragarea .button{ margin:0 auto; } .js-drag-file{ overflow: hidden; width: 1px; height: 1px; opacity: 0; } .js-drag .js-drag-fileinfo, .js-drag .js-drag-clear{ display: none; color: #000; font-weight: 400; font-size: 15px; line-height: 1.5; } .js-drag .js-drag-clear{ text-transform: uppercase; font-size: 13px; width: 80px; margin: 10px auto 0 auto; } .js-drag .js-drag-fileinfo:first-line{ color: #b2b2b2; } .js-drag.filled .js-drag-fileinfo, .js-drag.filled .js-drag-clear{ display: block; } .js-drag.filled p, .js-drag.filled .button{ display: none; } |
表单提交后的处理:
还是通过Rest API保存文件,保存后获取到文件地址以做后续其他工作。注意要上传文件就必须要身份验证,身份验证的接口上一篇文章也说了,先安装Basic-Auth插件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | //通过Rest API保存文件 function brain_wp_api_upload( $filedata ){ $file_url = $filedata['tmp_name']; $file_content=file_get_contents($file_url); $url_api = site_url("/wp-json/wp/v2/media/"); $file_name = $filedata['name']; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url_api ); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1 ); curl_setopt($ch, CURLOPT_POST, 1 ); curl_setopt($ch, CURLOPT_POSTFIELDS, $file_content); curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'content-disposition: attachment; filename="'.$file_name.'"', 'authorization: Basic ' . base64_encode('username:password') //'authorization: ' . $_SERVER['HTTP_AUTHORIZATION'] ) ); $result=curl_exec($ch); if(json_decode($result)->id){ return json_decode($result)->guid->rendered ; }else{ return json_decode($result)->data->status . " " .json_decode($result)->message; } } //获取提交的内容,并调用brain_wp_api_upload这个函数返回的文件URL if(!empty($_FILES['pro_document']['tmp_name'])){ $pro_document = brain_wp_api_upload( $_FILES['pro_document'] ); echo "pro_document: ".$pro_document. "<br/>"; }else{ $pro_document = ""; } ... //后续的一系列处理 |
最后,因为是对外使用的上传功能,还需要单独开设个子目录上传文件单独保存,以免和文章等其他附件混淆在一起。用upload_dir这个钩子,通过识别上传的用户id临时修改目录:
1 2 3 4 5 6 7 8 9 | add_filter( 'upload_dir', 'brain_change_upload_dir_ct' ); function brain_change_upload_dir_ct( $upload ) { if( get_current_user_id()== 2 ){//basic认证的用户id $upload['subdir'] = '/subfolder'; //子目录名 $upload['path'] = $upload['basedir'] . $upload['subdir']; $upload['url'] = $upload['baseurl'] . $upload['subdir']; } return $upload; } |
其实后来找了下Gravity Forms也有实现类似功能的外挂,比如这个,前端是原生的也有,比如 这个。可惜这些都不完全符合我的应用场景。在提交表单之前,我只想让用户先选定本地文件,而并不是立即上传,我表单里还有很多其他选项以及用了验证码系统,在表单提交后通过验证,再上传文件,这样可以避免网站被滥传一些无用的文件甚至是木马。
本站所有文章均为原创,欢迎转载,请注明文章出处:https://blog.brain1981.com/2263.html。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。
您也可以扫描左边的二维码,关注我们的微信公众号,在微信上查看我们的案例。